Hibernate SVN: r11253 - in branches/Branch_3_2/HibernateExt/search: doc/reference/en/modules and 5 other directories.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-03-06 00:23:23 -0500 (Tue, 06 Mar 2007)
New Revision: 11253
Added:
branches/Branch_3_2/HibernateExt/search/doc/reference/en/images/jms-backend.png
branches/Branch_3_2/HibernateExt/search/doc/reference/en/images/lucene-backend.png
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSSlaveDirectoryProvider.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/FSSlaveAndMasterDPTest.java
Removed:
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSSwitchableDirectoryProvider.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/FSSwitchableAndMasterDPTest.java
Modified:
branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/architecture.xml
branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/configuration.xml
branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/mapping.xml
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/Environment.java
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSMasterDirectoryProvider.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/AsyncWorkerTest.java
Log:
Documentation and better property names
Added: branches/Branch_3_2/HibernateExt/search/doc/reference/en/images/jms-backend.png
===================================================================
(Binary files differ)
Property changes on: branches/Branch_3_2/HibernateExt/search/doc/reference/en/images/jms-backend.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: branches/Branch_3_2/HibernateExt/search/doc/reference/en/images/lucene-backend.png
===================================================================
(Binary files differ)
Property changes on: branches/Branch_3_2/HibernateExt/search/doc/reference/en/images/lucene-backend.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Modified: branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/architecture.xml
===================================================================
--- branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/architecture.xml 2007-03-06 05:19:39 UTC (rev 11252)
+++ branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/architecture.xml 2007-03-06 05:23:23 UTC (rev 11253)
@@ -6,17 +6,10 @@
engine. Both are backed by Apache Lucene.</para>
<para>When an entity is inserted, updated or removed to/from the database,
- <productname>Hibernate Search</productname> will keep track of this event
- (through the Hibernate event system) and schedule an index update. When out
- of transaction, the update is executed right after the actual database
- operation. It is however recommended, for both your database and Hibernate
- Search, to execute your operation in a transaction (whether JDBC or JTA).
- When in a transaction, the index update is schedule for the transaction
- commit (and discarded in case of transaction rollback). You can think of
- this as the regular (infamous) autocommit vs transactional behavior. From a
- performance perspective, the <emphasis>in transaction</emphasis> mode is
- recommended. All the index updates are handled for you without you having to
- use the Apache Lucene APIs.</para>
+ <productname>Hibernate Search</productname> keeps track of this event
+ (through the Hibernate event system) and schedule an index update. All the
+ index updates are handled for you without you having to use the Apache
+ Lucene APIs.</para>
<para>To interact with Apache Lucene indexes, Hibernate Search has the
notion of <classname>DirectoryProvider</classname> . A directory provider
@@ -31,50 +24,163 @@
native query would be done.</para>
<section>
- <title>Backend</title>
+ <title>Batching Scope</title>
- <para>Hibernate Search offers the ability to process the</para>
+ <para>To be more efficient, Hibernate Search batch the interactions with
+ the Lucene index. There is currently two types of batching depending on
+ the expected scope.</para>
+ <para>When out of transaction, the index update operation is executed
+ right after the actual database operation. This scope is really a no
+ scoping, and no batching is performed.</para>
+
+ <para>It is however recommended, for both your database and Hibernate
+ Search, to execute your operation in a transaction (whether it be JDBC or
+ JTA). When in a transaction, the index update operation is schedule for
+ the transaction commit (and discarded in case of transaction rollback).
+ The batching scope is the transaction. There is 2 immediate
+ benefits:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>performance: Lucene indexing works better when operation are
+ executed in batch.</para>
+ </listitem>
+
+ <listitem>
+ <para>ACIDity: The work executed has the same scoping as the one
+ executed by the database transaction and is executed if and only if
+ the transaction is committed.</para>
+
+ <note>
+ <para>Disclamer, the work in not ACID in the strict sense of it, but
+ ACID behavior is rarely useful for full text search indexes since
+ they can be rebuilt from the source at any time.</para>
+ </note>
+ </listitem>
+ </itemizedlist>
+
+ <para>You can think of those two scopes (no scope vs transactional) as the
+ equivalent of the (infamous) autocommit vs transactional behavior. From a
+ performance perspective, the <emphasis>in transaction</emphasis> mode is
+ recommended. The scoping choice is made transparently: Hibernate Search
+ detects the presence of a transaction and adjust the scoping.</para>
+
+ <remark>Note that Hibernate Search works perfectly fine in the Hibernate /
+ EntityManager long conversation pattern aka. atomic conversation.</remark>
+
+ <para>Depending on user demand, additional scoping will be considered, the
+ pluggability mechanism being already in place.</para>
+ </section>
+
+ <section>
+ <title>Back end</title>
+
+ <para>Hibernate Search offers the ability to let the scoped work being
+ processed by different back ends. Two back ends are provided out of the
+ box for 2 different scenarii.</para>
+
<section>
<title>Lucene</title>
<para>In this mode, all index update operations applied on a given node
(JVM) will be executed to the Lucene directories (through the directory
providers) by the same node. This mode is typically used in non
- clustered mode or in clustered mode where the directory store is shared.
- </para>
+ clustered mode or in clustered mode where the directory store is
+ shared.</para>
+
+ <mediaobject>
+ <imageobject role="html">
+ <imagedata align="center"
+ fileref="../shared/images/lucene-backend.png"
+ format="PNG" />
+ </imageobject>
+
+ <imageobject role="fo">
+ <imagedata align="center" fileref="images/lucene-backend.png"
+ format="PNG" />
+ </imageobject>
+ </mediaobject>
+
+ <para>This mode targets non clustered applications, or clustered
+ applications where the Directory is taking care of the locking
+ strategy.</para>
+
+ <para>The main advantage is simplicity and immediate visibility of the
+ changes in Lucene queries (a requirement is some applications).</para>
</section>
<section>
<title>JMS</title>
- <para></para>
+ <para>All index update operations applied on a given node are sent to a
+ JMS queue. A unique reader will then process the queue and update the
+ master Lucene index. The master index is then replicated on a regular
+ basis to the slave copies. This is known as the master / slaves pattern.
+ The master is the sole responsible for updating the Lucene index, the
+ slaves can accept read/write operations, process the read operation on
+ their local index copy, and delegate the update operations to the
+ master.</para>
+
+ <mediaobject>
+ <imageobject role="html">
+ <imagedata align="center" fileref="../shared/images/jms-backend.png"
+ format="PNG" />
+ </imageobject>
+
+ <imageobject role="fo">
+ <imagedata align="center" fileref="images/jms-backend.png"
+ format="PNG" />
+ </imageobject>
+ </mediaobject>
+
+ <para>This mode targets clustered environments where throughput is
+ critical, and index update delays are affordable. Reliability is ensured
+ by the JMS provider and by having the slaves working on a local copy of
+ the index.</para>
</section>
<section>
<title>Custom</title>
- <para></para>
+ <para>Hibernate Search is an extensible architecture. While not yet part
+ of the public API, pluging a third party back end is possible. Feel free
+ to drop ideas to
+ <literal>hibernate-dev(a)lists.jboss.org</literal>.</para>
</section>
</section>
<section>
<title>Work execution</title>
- <para>The indexing work can be executed synchronously with the transaction
- commit (or update operation if out of transaction), or
- asynchronously.</para>
+ <para>The indexing work (done by the back end) can be executed
+ synchronously with the transaction commit (or update operation if out of
+ transaction), or asynchronously.</para>
<section>
<title>Synchronous</title>
- <para></para>
+ <para>This is the safe mode where the back end work is executed in
+ concert with the transaction commit. Under highly concurrent
+ environment, this can lead to throughput limitation (due to the Apache
+ Lucene lock mechanism). It can increase the system response time too if
+ the backend is significantly slower than the transactional process and
+ if a lot of IO operations are involved.</para>
</section>
<section>
<title>Asynchronous</title>
- <para></para>
+ <para>This mode delegates the work done by the back end to a different
+ thread. That way, throughput and response time are (to a certain extend)
+ decorrelated from the back end performance. The drawback is that a small
+ delay appears between the transaction commit and the index update and a
+ small overhead is introduced to deal with thread management.</para>
+
+ <para>It is recommended to use synchronous execution first and evaluate
+ asynchronous if performance problems occur and after having set up a
+ proper benchmark (ie not a lonely cowboy hitting the system in a
+ completely unrealistic way).</para>
</section>
</section>
</chapter>
\ No newline at end of file
Modified: branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/configuration.xml
===================================================================
--- branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/configuration.xml 2007-03-06 05:19:39 UTC (rev 11252)
+++ branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/configuration.xml 2007-03-06 05:23:23 UTC (rev 11253)
@@ -46,6 +46,63 @@
<entry>none</entry>
</row>
+
+ <row>
+ <entry>org.hibernate.search.store.FSMasterDirectoryProvider</entry>
+
+ <entry><para>File system based directory. Like
+ FSDirectoryProvider. It also copy the index to a source directory
+ (aka copy directory) on a regular basis. </para><para>The
+ recommended value for the refresh period is (at least) 50% higher
+ that the time to copy the information (default 3600 seconds - 60
+ minutes).</para><para>Note that the copy is based on an
+ incremental copy mechanism reducing the average copy
+ time.</para><para>DirectoryProvider typically used on the master
+ node in a JMS back end cluster.</para>DirectoryProvider typically
+ used on slave nodes using a JMS back end.</entry>
+
+ <entry><para><literal>indexBase</literal>: Base
+ directory</para><para><literal>sourceBase</literal>: Source (copy)
+ base directory.</para><para><literal>source</literal>: Source
+ directory suffix (default to <literal>@Indexed.name</literal>).
+ The actual source directory name being
+ <filename><sourceBase>/<source></filename>
+ </para><para>refresh: refresh period in second (the copy will take
+ place every refresh seconds).</para></entry>
+ </row>
+
+ <row>
+ <entry>org.hibernate.search.store.FSSlaveDirectoryProvider</entry>
+
+ <entry><para>File system based directory. Like
+ FSDirectoryProvider. But retrieve a master version (source) on a
+ regular basis. To avoid locking and inconsistent search results, 2
+ local copies are kept. </para><para>The recommended value for the
+ refresh period is (at least) 50% higher that the time to copy the
+ information (default 3600 seconds - 60 minutes).</para><para>Note
+ that the copy is based on an incremental copy mechanism reducing
+ the average copy time.</para><para>DirectoryProvider typically
+ used on slave nodes using a JMS back end.</para></entry>
+
+ <entry><para><literal>indexBase</literal>: Base
+ directory</para><para><literal>sourceBase</literal>: Source (copy)
+ base directory.</para><para><literal>source</literal>: Source
+ directory suffix (default to <literal>@Indexed.name</literal>).
+ The actual source directory name being
+ <filename><sourceBase>/<source></filename>
+ </para><para>refresh: refresh period in second (the copy will take
+ place every refresh seconds).</para></entry>
+ </row>
+
+ <row>
+ <entry>org.hibernate.search.store.RAMDirectoryProvider</entry>
+
+ <entry>Memory based directory, the directory will be uniquely
+ identified (in the same deployment unit) by the
+ <literal>@Indexed.name</literal> element</entry>
+
+ <entry>none</entry>
+ </row>
</tbody>
</tgroup>
</table>
@@ -78,8 +135,7 @@
public class Status { ... }
@Indexed(name="Rules")
-public class Rule { ... }
- </programlisting>
+public class Rule { ... }</programlisting>
<para>will create a file system directory in
<filename>/usr/lucene/indexes/Status</filename> where the Status entities
@@ -94,6 +150,208 @@
benefit this configuration mechanism too.</para>
</section>
+ <section>
+ <title>Worker and Back ends configuration</title>
+
+ <para>Hibernate Search works done by a worker you can configure. The
+ default (and only) worker today use transactional scoping.</para>
+
+ <section>
+ <title>Generic configuration</title>
+
+ <para>You can define the worker configuration using the following
+ properties</para>
+
+ <para></para>
+
+ <table>
+ <title>worker configuration</title>
+
+ <tgroup cols="2">
+ <colspec align="center" />
+
+ <tbody>
+ <row>
+ <entry>property</entry>
+
+ <entry>description</entry>
+ </row>
+
+ <row>
+ <entry><literal>org.hibernate.worker.backend</literal></entry>
+
+ <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>.</entry>
+ </row>
+
+ <row>
+ <entry><literal>org.hibernate.worker.execution</literal></entry>
+
+ <entry>Supports synchronous and asynchrounous execution. Default
+ to <literal><literal>sync</literal></literal>. Supports also
+ <literal>async</literal>.</entry>
+ </row>
+
+ <row>
+ <entry><literal>org.hibernate.worker.thread_pool.size</literal></entry>
+
+ <entry>Defines the number of threads in the pool. useful only
+ for asynchrounous execution. Default to 1.</entry>
+ </row>
+
+ <row>
+ <entry><literal>org.hibernate.worker.buffer_queue.max</literal></entry>
+
+ <entry>Defines the maximal number of work queue if the thread
+ poll is starved. Useful only for asynchrounous execution.
+ Default to infinite. If the limit is reached, the work is done
+ by the main thread.</entry>
+ </row>
+
+ <row>
+ <entry><literal>org.hibernate.worker.jndi.*</literal></entry>
+
+ <entry>Defines the JNDI properties to initiate the
+ InitialContext (if needed). JNDI is only used by the JMS back
+ end.</entry>
+ </row>
+
+ <row>
+ <entry><literal>
+ org.hibernate.worker.jms.connection_factory</literal></entry>
+
+ <entry>Mandatory for the JMS back end. Defines the JNDI name to
+ lookup the JMS connection factory from
+ (<literal>java:/ConnectionFactory</literal> by default in JBoss
+ AS)</entry>
+ </row>
+
+ <row>
+ <entry><literal>
+ org.hibernate.worker.jms.queue</literal></entry>
+
+ <entry>Mandatory for the JMS back end. Defines the JNDI name to
+ lookup the JMS queue from. The queue will be used to post work
+ messages.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+
+ <section>
+ <title>JMS Back end</title>
+
+ <para>This chapter describes in greater detail how to configure the
+ Master / Slaves Hibernate Search architecture.</para>
+
+ <section>
+ <title>Slave nodes</title>
+
+ <para>Every index update operation is sent to a JMS queue. Index
+ quering operations are executed on a local index copy.</para>
+
+ <programlisting>### slave configuration
+
+## DirectoryProvider
+# (remote) master location
+hibernate.search.default.sourceBase = /mnt/mastervolume/lucenedirs/mastercopy
+
+# local copy location
+hibernate.search.default.indexBase = /Users/prod/lucenedirs
+
+# refresh every half hour
+hibernate.search.default.refresh = 1800
+
+# appropriate directory provider
+hibernate.search.default.directory_provider = org.hibernate.search.store.FSSlaveDirectoryProvider
+
+## Backend configuration
+hibernate.search.worker.backend = jms
+hibernate.search.worker.jms.connection_factory = java:/ConnectionFactory
+hibernate.search.worker.jms.queue = queue/hibernatesearch
+#optional jndi configuration (check your JMS provider for more information)
+
+## Optional asynchronous execution strategy
+# org.hibernate.worker.execution = async
+# org.hibernate.worker.thread_pool.size = 2
+# org.hibernate.worker.buffer_queue.max = 50</programlisting>
+
+ <para>A file system local copy is recommended for faster search
+ results.</para>
+
+ <para>The refresh period should be higher that the expected time
+ copy.</para>
+ </section>
+
+ <section>
+ <title>Master node</title>
+
+ <para>Every index update operation is taken fron a JMS queue and
+ executed. The master index(es) is(are) copied on a regular
+ basis.</para>
+
+ <programlisting>### master configuration
+
+## DirectoryProvider
+# (remote) master location where information is copied to
+hibernate.search.default.sourceBase = /mnt/mastervolume/lucenedirs/mastercopy
+
+# local master location
+hibernate.search.default.indexBase = /Users/prod/lucenedirs
+
+# refresh every half hour
+hibernate.search.default.refresh = 1800
+
+# appropriate directory provider
+hibernate.search.default.directory_provider = org.hibernate.search.store.FSMasterDirectoryProvider
+
+## Backend configuration
+#Backend is the default lucene one</programlisting>
+
+ <para>The refresh period should be higher that the expected time
+ copy.</para>
+
+ <para>In addition to the Hibernate Search framework configuration, a
+ Message Driven Bean should be written and set up to process index
+ works queue through JMS.</para>
+
+ <programlisting>@MessageDriven(activationConfig = {
+ @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName="destination", propertyValue="queue/hiebrnatesearch"),
+ @ActivationConfigProperty(propertyName="DLQMaxResent", propertyValue="1")
+ } )
+public class MDBSearchController extends AbstractJMSHibernateSearchController implements MessageListener {
+ @PersistenceContext EntityManager em;
+
+ //method retrieving the appropriate session
+ protected Session getSession() {
+ return (Session) em.getDelegate();
+ }
+
+ //potentially close the session opened in #getSession(), not needed here
+ protected void cleanSessionIfNeeded(Session session)
+ }
+}</programlisting>
+
+ <para>This example inherit the abstract JMS controller class available
+ and implements a JavaEE 5 MDB. This implementation is given as an
+ example and, while most likely ;ore complex, can be adjusted to make
+ use of non Java EE Message Driven Beans. For more information about
+ the <methodname>getSession()</methodname> and
+ <methodname>cleanSessionIfNeeded()</methodname>, please check
+ <classname>AbstractJMSHibernateSearchController</classname>'s
+ javadoc.</para>
+
+ <remark>Hibernate Search test suite makes use of JBoss Embedded to
+ test the JMS integration. It allows the unit test to run both the MDB
+ container and JBoss Messaging (JMS provider) in a standalone way
+ (marketed by some as "lightweight"). </remark>
+ </section>
+ </section>
+ </section>
+
<section id="search-configuration-event" revision="1">
<title>Enabling automatic indexing</title>
@@ -104,9 +362,11 @@
that there is no performance runtime when the listeners are enabled while
no entity is indexable.</para>
- <para>To enable automatic indexing in Hibernate core, add the
+ <para>To enable automatic indexing in Hibernate Core, add the
<literal>SearchEventListener</literal> for the three Hibernate events that
- occur after changes are executed to the database.</para>
+ occur after changes are executed to the database. Once again, such a
+ configuration is not useful with Hibernate Annotations or Hibernate
+ EntityManager.</para>
<programlisting><hibernate-configuration>
...
Modified: branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/mapping.xml
===================================================================
--- branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/mapping.xml 2007-03-06 05:19:39 UTC (rev 11252)
+++ branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/mapping.xml 2007-03-06 05:23:23 UTC (rev 11253)
@@ -19,8 +19,7 @@
<emphasis role="bold">@Indexed(index="indexes/essays")</emphasis>
public class Essay {
...
-}
- </programlisting>
+}</programlisting>
<para>The <literal>index</literal> attribute tells Hibernate what the
Lucene directory name is (usually a directory on your file system). If you
Modified: branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/Environment.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/Environment.java 2007-03-06 05:19:39 UTC (rev 11252)
+++ branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/Environment.java 2007-03-06 05:23:23 UTC (rev 11253)
@@ -22,5 +22,17 @@
public static final String WORKER_PREFIX = "hibernate.search.worker.";
public static final String WORKER_SCOPE = WORKER_PREFIX + "scope";
public static final String WORKER_BACKEND = WORKER_PREFIX + "backend";
- public static final String WORKER_PROCESS = WORKER_PREFIX + "process";
+ public static final String WORKER_EXECUTION = WORKER_PREFIX + "execution";
+ /**
+ * only used then execution is async
+ * Thread pool size
+ * default 1
+ */
+ public static final String WORKER_THREADPOOL_SIZE = Environment.WORKER_PREFIX + "thread_pool.size";
+ /**
+ * only used then execution is async
+ * Size of the buffer queue (besides the thread pool size)
+ * default infinite
+ */
+ public static final String WORKER_WORKQUEUE_SIZE = Environment.WORKER_PREFIX + "buffer_queue.max";
}
Modified: branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java 2007-03-06 05:19:39 UTC (rev 11252)
+++ branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java 2007-03-06 05:23:23 UTC (rev 11253)
@@ -36,18 +36,29 @@
public BatchedQueueingProcessor(SearchFactory searchFactory,
Properties properties) {
//default to sync if none defined
- this.sync = !"async".equalsIgnoreCase( properties.getProperty( Environment.WORKER_PROCESS ) );
+ this.sync = !"async".equalsIgnoreCase( properties.getProperty( Environment.WORKER_EXECUTION ) );
+ //default to a simple asynchronous operation
int min = Integer.parseInt(
- properties.getProperty( Environment.WORKER_PREFIX + "thread_pool.min", "0" )
+ properties.getProperty( Environment.WORKER_THREADPOOL_SIZE, "1" ).trim()
);
- int max = Integer.parseInt(
- properties.getProperty( Environment.WORKER_PREFIX + "thread_pool.max", "0" ).trim()
+ //no queue limit
+ int queueSize = Integer.parseInt(
+ properties.getProperty( Environment.WORKER_WORKQUEUE_SIZE, Integer.toString( Integer.MAX_VALUE ) ).trim()
);
- if ( max == 0 ) max = Integer.MAX_VALUE;
if ( !sync ) {
- executorService =
- new ThreadPoolExecutor( min, max, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>() );
+ /**
+ * choose min = max with a sizable queue to be able to
+ * actually queue operations
+ * The locking mechanism preventing much of the scalability
+ * anyway, the idea is really to have a buffer
+ * If the queue limit is reached, the operation is executed by the main thread
+ */
+ executorService = new ThreadPoolExecutor(
+ min, min, 60, TimeUnit.SECONDS,
+ new LinkedBlockingQueue<Runnable>(queueSize),
+ new ThreadPoolExecutor.CallerRunsPolicy()
+ );
}
String backend = properties.getProperty( Environment.WORKER_BACKEND );
if ( StringHelper.isEmpty( backend ) || "lucene".equalsIgnoreCase( backend ) ) {
Modified: branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSMasterDirectoryProvider.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSMasterDirectoryProvider.java 2007-03-06 05:19:39 UTC (rev 11252)
+++ branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSMasterDirectoryProvider.java 2007-03-06 05:23:23 UTC (rev 11253)
@@ -21,12 +21,13 @@
import org.hibernate.HibernateException;
/**
- * Use a Lucene FSDirectory
+ * File based DirectoryProvider that takes care of index copy
* The base directory is represented by hibernate.search.<index>.indexBase
* The index is created in <base directory>/<index name>
- * The copy directory is built from <sourceBase>/<index name>
- * TODO explose source
+ * The source (aka copy) directory is built from <sourceBase>/<index name>
*
+ * A copy is triggered every refresh seconds
+ *
* @author Emmanuel Bernard
*/
//TODO rename copy?
@@ -46,10 +47,10 @@
log.debug( "Source directory: " + source );
File indexDir = DirectoryProviderHelper.determineIndexDir( directoryProviderName, properties );
log.debug( "Index directory: " + indexDir );
- String refreshPeriod = properties.getProperty( "refresh", "60" );
+ String refreshPeriod = properties.getProperty( "refresh", "3600" );
long period = Long.parseLong( refreshPeriod );
- period *= 100 * 60; //per minute
- log.debug("Refresh period " + period / 1000 + " mins");
+ log.debug("Refresh period " + period + " seconds");
+ period *= 1000; //per second
try {
boolean create = !indexDir.exists();
indexName = indexDir.getCanonicalPath();
Copied: branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSSlaveDirectoryProvider.java (from rev 11246, branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSSwitchableDirectoryProvider.java)
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSSlaveDirectoryProvider.java (rev 0)
+++ branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSSlaveDirectoryProvider.java 2007-03-06 05:23:23 UTC (rev 11253)
@@ -0,0 +1,239 @@
+//$Id: $
+package org.hibernate.search.store;
+
+import java.util.Properties;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.lucene.store.FSDirectory;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.search.util.FileHelper;
+import org.hibernate.search.util.DirectoryProviderHelper;
+import org.hibernate.search.SearchFactory;
+
+/**
+ * File based directory provider that takes care of geting a version of the index
+ * from a given source
+ * The base directory is represented by hibernate.search.<index>.indexBase
+ * The index is created in <base directory>/<index name>
+ * The source (aka copy) directory is built from <sourceBase>/<index name>
+ *
+ * A copy is triggered every refresh seconds
+ *
+ * @author Emmanuel Bernard
+ */
+public class FSSlaveDirectoryProvider implements DirectoryProvider<FSDirectory> {
+ private static Log log = LogFactory.getLog( FSSlaveDirectoryProvider.class );
+ private FSDirectory directory1;
+ private FSDirectory directory2;
+ private int current;
+ private String indexName;
+ private Timer timer;
+
+ public void initialize(String directoryProviderName, Properties properties, SearchFactory searchFactory) {
+ //source guessing
+ String source = DirectoryProviderHelper.getSourceDirectory( "sourceBase", "source", directoryProviderName, properties );
+ if (source == null)
+ throw new IllegalStateException("FSSlaveDirectoryProvider requires a viable source directory");
+ if ( ! new File(source, "current1").exists() && ! new File(source, "current2").exists() ) {
+ throw new IllegalStateException("No current marker in source directory");
+ }
+ log.debug( "Source directory: " + source );
+ File indexDir = DirectoryProviderHelper.determineIndexDir( directoryProviderName, properties );
+ log.debug( "Index directory: " + indexDir.getPath() );
+ String refreshPeriod = properties.getProperty( "refresh", "3600" );
+ long period = Long.parseLong( refreshPeriod );
+ log.debug("Refresh period " + period + " seconds");
+ period *= 1000; //per second
+ try {
+ boolean create = !indexDir.exists();
+ indexName = indexDir.getCanonicalPath();
+ if (create) {
+ indexDir.mkdir();
+ log.debug("Initializing index directory " + indexName);
+ }
+
+ File subDir = new File( indexName, "1" );
+ create = ! subDir.exists();
+ directory1 = FSDirectory.getDirectory( subDir.getCanonicalPath(), create );
+ if ( create ) {
+ IndexWriter iw = new IndexWriter( directory1, new StandardAnalyzer(), create );
+ iw.close();
+ }
+
+ subDir = new File( indexName, "2" );
+ create = ! subDir.exists();
+ directory2 = FSDirectory.getDirectory( subDir.getCanonicalPath(), create );
+ if ( create ) {
+ IndexWriter iw = new IndexWriter( directory2, new StandardAnalyzer(), create );
+ iw.close();
+ }
+ File currentMarker = new File(indexName, "current1");
+ File current2Marker = new File(indexName, "current2");
+ if ( currentMarker.exists() ) {
+ current = 1;
+ }
+ else if ( current2Marker.exists() ) {
+ current = 2;
+ }
+ else {
+ //no default
+ log.debug( "Setting directory 1 as current");
+ current = 1;
+ File sourceFile = new File(source);
+ File destinationFile = new File(indexName, Integer.valueOf(current).toString() );
+ int sourceCurrent;
+ if ( new File(sourceFile, "current1").exists() ) {
+ sourceCurrent = 1;
+ }
+ else if ( new File(sourceFile, "current2").exists() ) {
+ sourceCurrent = 2;
+ }
+ else {
+ throw new AssertionFailure("No current file marker found in source directory: " + source);
+ }
+ try {
+ FileHelper.synchronize( new File(sourceFile, String.valueOf(sourceCurrent) ), destinationFile, true);
+ }
+ catch (IOException e) {
+ throw new HibernateException("Umable to synchonize directory: " + indexName, e);
+ }
+ if (! currentMarker.createNewFile() ) {
+ throw new HibernateException("Unable to create the directory marker file: " + indexName);
+ }
+ }
+ log.debug( "Current directory: " + current);
+ }
+ catch (IOException e) {
+ throw new HibernateException( "Unable to initialize index: " + directoryProviderName, e );
+ }
+ timer = new Timer();
+ TimerTask task = new TriggerTask(source, indexName);
+ timer.scheduleAtFixedRate( task, period, period );
+ }
+
+ public FSDirectory getDirectory() {
+ if (current == 1) {
+ return directory1;
+ }
+ else if (current == 2) {
+ return directory2;
+ }
+ else {
+ throw new AssertionFailure("Illegal current directory: " + current);
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ // this code is actually broken since the value change after initialize call
+ // but from a practical POV this is fine since we only call this method
+ // after initialize call
+ if ( obj == this ) return true;
+ if ( obj == null || !( obj instanceof FSSlaveDirectoryProvider ) ) return false;
+ return indexName.equals( ( (FSSlaveDirectoryProvider) obj ).indexName );
+ }
+
+ @Override
+ public int hashCode() {
+ // this code is actually broken since the value change after initialize call
+ // but from a practical POV this is fine since we only call this method
+ // after initialize call
+ int hash = 11;
+ return 37 * hash + indexName.hashCode();
+ }
+
+ class TriggerTask extends TimerTask {
+
+ private ExecutorService executor;
+ private CopyDirectory copyTask;
+
+ public TriggerTask(String source, String destination) {
+ executor = Executors.newSingleThreadExecutor();
+ copyTask = new CopyDirectory( source, destination );
+ }
+
+ public void run() {
+ if (!copyTask.inProgress) {
+ executor.execute( copyTask );
+ }
+ else {
+ log.trace( "Skipping directory synchronization, previous work still in progress: " + indexName);
+ }
+ }
+ }
+
+ class CopyDirectory implements Runnable {
+ private String source;
+ private String destination;
+ private volatile boolean inProgress;
+
+ public CopyDirectory(String source, String destination) {
+ this.source = source;
+ this.destination = destination;
+ }
+
+ public void run() {
+ long start = System.currentTimeMillis();
+ try {
+ inProgress = true;
+ int oldIndex = current;
+ int index = current == 1 ? 2 : 1;
+ File sourceFile;
+ if ( new File( source, "current1" ).exists() ) {
+ sourceFile = new File(source, "1");
+ }
+ else if ( new File( source, "current2" ).exists() ) {
+ sourceFile = new File(source, "2");
+ }
+ else {
+ log.error("Unable to determine current in source directory");
+ inProgress = false;
+ return;
+ }
+
+ File destinationFile = new File(destination, Integer.valueOf(index).toString() );
+ //TODO make smart a parameter
+ try {
+ log.trace("Copying " + sourceFile + " into " + destinationFile);
+ FileHelper.synchronize( sourceFile, destinationFile, true);
+ current = index;
+ }
+ catch (IOException e) {
+ //don't change current
+ log.error( "Unable to synchronize " + indexName, e);
+ inProgress = false;
+ return;
+ }
+ if ( ! new File(indexName, "current" + oldIndex).delete() ) {
+ log.warn( "Unable to remove previous marker file in " + indexName );
+ }
+ try {
+ new File(indexName, "current" + index).createNewFile();
+ }
+ catch( IOException e ) {
+ log.warn( "Unable to create current marker file in " + indexName, e );
+ }
+ }
+ finally {
+ inProgress = false;
+ }
+ log.trace( "Copy for " + indexName + " took " + (System.currentTimeMillis() - start) + " ms");
+ }
+ }
+
+ public void finalize() throws Throwable {
+ super.finalize();
+ timer.cancel();
+ //TODO find a better cycle from Hibernate core
+ }
+}
Deleted: branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSSwitchableDirectoryProvider.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSSwitchableDirectoryProvider.java 2007-03-06 05:19:39 UTC (rev 11252)
+++ branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSSwitchableDirectoryProvider.java 2007-03-06 05:23:23 UTC (rev 11253)
@@ -1,235 +0,0 @@
-//$Id: $
-package org.hibernate.search.store;
-
-import java.util.Properties;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.io.File;
-import java.io.IOException;
-
-import org.apache.lucene.store.FSDirectory;
-import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.analysis.standard.StandardAnalyzer;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.hibernate.HibernateException;
-import org.hibernate.AssertionFailure;
-import org.hibernate.search.util.FileHelper;
-import org.hibernate.search.util.DirectoryProviderHelper;
-import org.hibernate.search.SearchFactory;
-
-/**
- * Use a Lucene FSDirectory
- * The base directory is represented by hibernate.search.<index>.indexBase
- * The index is created in <base directory>/<index name>
- *
- * @author Emmanuel Bernard
- */
-public class FSSwitchableDirectoryProvider implements DirectoryProvider<FSDirectory> {
- private static Log log = LogFactory.getLog( FSSwitchableDirectoryProvider.class );
- private FSDirectory directory1;
- private FSDirectory directory2;
- private int current;
- private String indexName;
- private Timer timer;
-
- public void initialize(String directoryProviderName, Properties properties, SearchFactory searchFactory) {
- //source guessing
- String source = DirectoryProviderHelper.getSourceDirectory( "sourceBase", "source", directoryProviderName, properties );
- if (source == null)
- throw new IllegalStateException("FSSwitchableDirectoryProvider requires a viable source directory");
- if ( ! new File(source, "current1").exists() && ! new File(source, "current2").exists() ) {
- throw new IllegalStateException("No current marker in source directory");
- }
- log.debug( "Source directory: " + source );
- File indexDir = DirectoryProviderHelper.determineIndexDir( directoryProviderName, properties );
- log.debug( "Index directory: " + indexDir.getPath() );
- String refreshPeriod = properties.getProperty( "refresh", "60" );
- long period = Long.parseLong( refreshPeriod );
- period *= 100 * 60; //per minute
- log.debug("Refresh period " + period / 60000 + " mins");
- try {
- boolean create = !indexDir.exists();
- indexName = indexDir.getCanonicalPath();
- if (create) {
- indexDir.mkdir();
- log.debug("Initializing index directory " + indexName);
- }
-
- File subDir = new File( indexName, "1" );
- create = ! subDir.exists();
- directory1 = FSDirectory.getDirectory( subDir.getCanonicalPath(), create );
- if ( create ) {
- IndexWriter iw = new IndexWriter( directory1, new StandardAnalyzer(), create );
- iw.close();
- }
-
- subDir = new File( indexName, "2" );
- create = ! subDir.exists();
- directory2 = FSDirectory.getDirectory( subDir.getCanonicalPath(), create );
- if ( create ) {
- IndexWriter iw = new IndexWriter( directory2, new StandardAnalyzer(), create );
- iw.close();
- }
- File currentMarker = new File(indexName, "current1");
- File current2Marker = new File(indexName, "current2");
- if ( currentMarker.exists() ) {
- current = 1;
- }
- else if ( current2Marker.exists() ) {
- current = 2;
- }
- else {
- //no default
- log.debug( "Setting directory 1 as current");
- current = 1;
- File sourceFile = new File(source);
- File destinationFile = new File(indexName, Integer.valueOf(current).toString() );
- int sourceCurrent;
- if ( new File(sourceFile, "current1").exists() ) {
- sourceCurrent = 1;
- }
- else if ( new File(sourceFile, "current2").exists() ) {
- sourceCurrent = 2;
- }
- else {
- throw new AssertionFailure("No current file marker found in source directory: " + source);
- }
- try {
- FileHelper.synchronize( new File(sourceFile, String.valueOf(sourceCurrent) ), destinationFile, true);
- }
- catch (IOException e) {
- throw new HibernateException("Umable to synchonize directory: " + indexName, e);
- }
- if (! currentMarker.createNewFile() ) {
- throw new HibernateException("Unable to create the directory marker file: " + indexName);
- }
- }
- log.debug( "Current directory: " + current);
- }
- catch (IOException e) {
- throw new HibernateException( "Unable to initialize index: " + directoryProviderName, e );
- }
- timer = new Timer();
- TimerTask task = new TriggerTask(source, indexName);
- timer.scheduleAtFixedRate( task, period, period );
- }
-
- public FSDirectory getDirectory() {
- if (current == 1) {
- return directory1;
- }
- else if (current == 2) {
- return directory2;
- }
- else {
- throw new AssertionFailure("Illegal current directory: " + current);
- }
- }
-
- @Override
- public boolean equals(Object obj) {
- // this code is actually broken since the value change after initialize call
- // but from a practical POV this is fine since we only call this method
- // after initialize call
- if ( obj == this ) return true;
- if ( obj == null || !( obj instanceof FSSwitchableDirectoryProvider ) ) return false;
- return indexName.equals( ( (FSSwitchableDirectoryProvider) obj ).indexName );
- }
-
- @Override
- public int hashCode() {
- // this code is actually broken since the value change after initialize call
- // but from a practical POV this is fine since we only call this method
- // after initialize call
- int hash = 11;
- return 37 * hash + indexName.hashCode();
- }
-
- class TriggerTask extends TimerTask {
-
- private ExecutorService executor;
- private CopyDirectory copyTask;
-
- public TriggerTask(String source, String destination) {
- executor = Executors.newSingleThreadExecutor();
- copyTask = new CopyDirectory( source, destination );
- }
-
- public void run() {
- if (!copyTask.inProgress) {
- executor.execute( copyTask );
- }
- else {
- log.trace( "Skipping directory synchronization, previous work still in progress: " + indexName);
- }
- }
- }
-
- class CopyDirectory implements Runnable {
- private String source;
- private String destination;
- private volatile boolean inProgress;
-
- public CopyDirectory(String source, String destination) {
- this.source = source;
- this.destination = destination;
- }
-
- public void run() {
- long start = System.currentTimeMillis();
- try {
- inProgress = true;
- int oldIndex = current;
- int index = current == 1 ? 2 : 1;
- File sourceFile;
- if ( new File( source, "current1" ).exists() ) {
- sourceFile = new File(source, "1");
- }
- else if ( new File( source, "current2" ).exists() ) {
- sourceFile = new File(source, "2");
- }
- else {
- log.error("Unable to determine current in source directory");
- inProgress = false;
- return;
- }
-
- File destinationFile = new File(destination, Integer.valueOf(index).toString() );
- //TODO make smart a parameter
- try {
- log.trace("Copying " + sourceFile + " into " + destinationFile);
- FileHelper.synchronize( sourceFile, destinationFile, true);
- current = index;
- }
- catch (IOException e) {
- //don't change current
- log.error( "Unable to synchronize " + indexName, e);
- inProgress = false;
- return;
- }
- if ( ! new File(indexName, "current" + oldIndex).delete() ) {
- log.warn( "Unable to remove previous marker file in " + indexName );
- }
- try {
- new File(indexName, "current" + index).createNewFile();
- }
- catch( IOException e ) {
- log.warn( "Unable to create current marker file in " + indexName, e );
- }
- }
- finally {
- inProgress = false;
- }
- log.trace( "Copy for " + indexName + " took " + (System.currentTimeMillis() - start) + " ms");
- }
- }
-
- public void finalize() throws Throwable {
- super.finalize();
- timer.cancel();
- //TODO find a better cycle from Hibernate core
- }
-}
Copied: branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/FSSlaveAndMasterDPTest.java (from rev 11246, branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/FSSwitchableAndMasterDPTest.java)
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/FSSlaveAndMasterDPTest.java (rev 0)
+++ branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/FSSlaveAndMasterDPTest.java 2007-03-06 05:23:23 UTC (rev 11253)
@@ -0,0 +1,137 @@
+//$Id: $
+package org.hibernate.search.test.directoryProvider;
+
+import java.io.File;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.lucene.analysis.StopAnalyzer;
+import org.apache.lucene.queryParser.QueryParser;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.event.PostDeleteEventListener;
+import org.hibernate.event.PostInsertEventListener;
+import org.hibernate.event.PostUpdateEventListener;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.Search;
+import org.hibernate.search.event.FullTextIndexEventListener;
+import org.hibernate.search.util.FileHelper;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class FSSlaveAndMasterDPTest extends MultipleSFTestCase {
+
+ public void testProperCopy() throws Exception {
+ Session s1 = getSessionFactories()[0].openSession( );
+ SnowStorm sn = new SnowStorm();
+ sn.setDate( new Date() );
+ sn.setLocation( "Dallas, TX, USA");
+
+ FullTextSession fts2 = Search.createFullTextSession( getSessionFactories()[1].openSession( ) );
+ QueryParser parser = new QueryParser("id", new StopAnalyzer() );
+ List result = fts2.createFullTextQuery( parser.parse( "location:texas" ) ).list();
+ assertEquals( "No copy yet, fresh index expected", 0, result.size() );
+
+ s1.persist( sn );
+ s1.flush(); //we don' commit so we need to flush manually
+
+ fts2.close();
+ s1.close();
+
+ Thread.sleep( 2 * 60 * 100 + 10); //wait a bit more than 2 refresh (one master / one slave)
+
+ //temp test original
+ fts2 = Search.createFullTextSession( getSessionFactories()[0].openSession( ) );
+ result = fts2.createFullTextQuery( parser.parse( "location:dallas" ) ).list();
+ assertEquals( "Original should get one", 1, result.size() );
+
+ fts2 = Search.createFullTextSession( getSessionFactories()[1].openSession( ) );
+ result = fts2.createFullTextQuery( parser.parse( "location:dallas" ) ).list();
+ assertEquals("First copy did not work out", 1, result.size() );
+
+ s1 = getSessionFactories()[0].openSession( );
+ sn = new SnowStorm();
+ sn.setDate( new Date() );
+ sn.setLocation( "Chennai, India");
+
+ s1.persist( sn );
+ s1.flush(); //we don' commit so we need to flush manually
+
+ fts2.close();
+ s1.close();
+
+ Thread.sleep( 2 * 60 * 100 + 10); //wait a bit more than 2 refresh (one master / one slave)
+
+ fts2 = Search.createFullTextSession( getSessionFactories()[1].openSession( ) );
+ result = fts2.createFullTextQuery( parser.parse( "location:chennai" ) ).list();
+ assertEquals("Second copy did not work out", 1, result.size() );
+
+ s1 = getSessionFactories()[0].openSession( );
+ sn = new SnowStorm();
+ sn.setDate( new Date() );
+ sn.setLocation( "Melbourne, Australia");
+
+ s1.persist( sn );
+ s1.flush(); //we don' commit so we need to flush manually
+
+ fts2.close();
+ s1.close();
+
+ Thread.sleep( 2 * 60 * 100 + 10); //wait a bit more than 2 refresh (one master / one slave)
+
+ fts2 = Search.createFullTextSession( getSessionFactories()[1].openSession( ) );
+ result = fts2.createFullTextQuery( parser.parse( "location:melbourne" ) ).list();
+ assertEquals("Third copy did not work out", 1, result.size() );
+
+ fts2.close();
+ }
+
+
+ protected void setUp() throws Exception {
+ File base = new File(".");
+ File root = new File(base, "lucenedirs");
+ root.mkdir();
+
+ File master = new File(root, "master/main");
+ master.mkdirs();
+ master = new File(root, "master/copy");
+ master.mkdirs();
+
+ File slave = new File(root, "slave");
+ slave.mkdir();
+
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ File base = new File(".");
+ File root = new File(base, "lucenedirs");
+ FileHelper.delete( root );
+ }
+
+ protected int getSFNbrs() {
+ return 2;
+ }
+
+ protected Class[] getMappings() {
+ return new Class[] {
+ SnowStorm.class
+ };
+ }
+
+ protected void configure(Configuration[] cfg) {
+ //master
+ cfg[0].setProperty( "hibernate.search.default.sourceBase", "./lucenedirs/master/copy");
+ cfg[0].setProperty( "hibernate.search.default.indexBase", "./lucenedirs/master/main");
+ cfg[0].setProperty( "hibernate.search.default.refresh", "1"); //every minute
+ cfg[0].setProperty( "hibernate.search.default.directory_provider", "org.hibernate.search.store.FSMasterDirectoryProvider");
+
+ //slave(s)
+ cfg[1].setProperty( "hibernate.search.default.sourceBase", "./lucenedirs/master/copy");
+ cfg[1].setProperty( "hibernate.search.default.indexBase", "./lucenedirs/slave");
+ cfg[1].setProperty( "hibernate.search.default.refresh", "1"); //every minute
+ cfg[1].setProperty( "hibernate.search.default.directory_provider", "org.hibernate.search.store.FSSlaveDirectoryProvider");
+ }
+}
Deleted: branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/FSSwitchableAndMasterDPTest.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/FSSwitchableAndMasterDPTest.java 2007-03-06 05:19:39 UTC (rev 11252)
+++ branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/FSSwitchableAndMasterDPTest.java 2007-03-06 05:23:23 UTC (rev 11253)
@@ -1,143 +0,0 @@
-//$Id: $
-package org.hibernate.search.test.directoryProvider;
-
-import java.io.File;
-import java.util.Date;
-import java.util.List;
-
-import org.apache.lucene.analysis.StopAnalyzer;
-import org.apache.lucene.queryParser.QueryParser;
-import org.hibernate.Session;
-import org.hibernate.cfg.Configuration;
-import org.hibernate.event.PostDeleteEventListener;
-import org.hibernate.event.PostInsertEventListener;
-import org.hibernate.event.PostUpdateEventListener;
-import org.hibernate.search.FullTextSession;
-import org.hibernate.search.Search;
-import org.hibernate.search.util.FileHelper;
-import org.hibernate.search.event.FullTextIndexEventListener;
-
-/**
- * @author Emmanuel Bernard
- */
-public class FSSwitchableAndMasterDPTest extends MultipleSFTestCase {
-
- public void testProperCopy() throws Exception {
- Session s1 = getSessionFactories()[0].openSession( );
- SnowStorm sn = new SnowStorm();
- sn.setDate( new Date() );
- sn.setLocation( "Dallas, TX, USA");
-
- FullTextSession fts2 = Search.createFullTextSession( getSessionFactories()[1].openSession( ) );
- QueryParser parser = new QueryParser("id", new StopAnalyzer() );
- List result = fts2.createFullTextQuery( parser.parse( "location:texas" ) ).list();
- assertEquals( "No copy yet, fresh index expected", 0, result.size() );
-
- s1.persist( sn );
- s1.flush(); //we don' commit so we need to flush manually
-
- fts2.close();
- s1.close();
-
- Thread.sleep( 2 * 60 * 100 + 10); //wait a bit more than 2 refresh (one master / one slave)
-
- //temp test original
- fts2 = Search.createFullTextSession( getSessionFactories()[0].openSession( ) );
- result = fts2.createFullTextQuery( parser.parse( "location:dallas" ) ).list();
- assertEquals( "Original should get one", 1, result.size() );
-
- fts2 = Search.createFullTextSession( getSessionFactories()[1].openSession( ) );
- result = fts2.createFullTextQuery( parser.parse( "location:dallas" ) ).list();
- assertEquals("First copy did not work out", 1, result.size() );
-
- s1 = getSessionFactories()[0].openSession( );
- sn = new SnowStorm();
- sn.setDate( new Date() );
- sn.setLocation( "Chennai, India");
-
- s1.persist( sn );
- s1.flush(); //we don' commit so we need to flush manually
-
- fts2.close();
- s1.close();
-
- Thread.sleep( 2 * 60 * 100 + 10); //wait a bit more than 2 refresh (one master / one slave)
-
- fts2 = Search.createFullTextSession( getSessionFactories()[1].openSession( ) );
- result = fts2.createFullTextQuery( parser.parse( "location:chennai" ) ).list();
- assertEquals("Second copy did not work out", 1, result.size() );
-
- s1 = getSessionFactories()[0].openSession( );
- sn = new SnowStorm();
- sn.setDate( new Date() );
- sn.setLocation( "Melbourne, Australia");
-
- s1.persist( sn );
- s1.flush(); //we don' commit so we need to flush manually
-
- fts2.close();
- s1.close();
-
- Thread.sleep( 2 * 60 * 100 + 10); //wait a bit more than 2 refresh (one master / one slave)
-
- fts2 = Search.createFullTextSession( getSessionFactories()[1].openSession( ) );
- result = fts2.createFullTextQuery( parser.parse( "location:melbourne" ) ).list();
- assertEquals("Third copy did not work out", 1, result.size() );
-
- fts2.close();
- }
-
-
- protected void setUp() throws Exception {
- File base = new File(".");
- File root = new File(base, "lucenedirs");
- root.mkdir();
-
- File master = new File(root, "master/main");
- master.mkdirs();
- master = new File(root, "master/copy");
- master.mkdirs();
-
- File slave = new File(root, "slave");
- slave.mkdir();
-
- super.setUp();
- }
-
- protected void tearDown() throws Exception {
- super.tearDown();
- File base = new File(".");
- File root = new File(base, "lucenedirs");
- FileHelper.delete( root );
- }
-
- protected int getSFNbrs() {
- return 2;
- }
-
- protected Class[] getMappings() {
- return new Class[] {
- SnowStorm.class
- };
- }
-
- protected void configure(Configuration[] cfg) {
- //master
- cfg[0].setProperty( "hibernate.search.default.sourceBase", "./lucenedirs/master/copy");
- cfg[0].setProperty( "hibernate.search.default.indexBase", "./lucenedirs/master/main");
- cfg[0].setProperty( "hibernate.search.default.refresh", "1"); //every minute
- cfg[0].setProperty( "hibernate.search.default.directory_provider", "org.hibernate.search.store.FSMasterDirectoryProvider");
- cfg[0].getEventListeners().setPostDeleteEventListeners( new PostDeleteEventListener[]{ new FullTextIndexEventListener() } );
- cfg[0].getEventListeners().setPostUpdateEventListeners( new PostUpdateEventListener[]{ new FullTextIndexEventListener() } );
- cfg[0].getEventListeners().setPostInsertEventListeners( new PostInsertEventListener[]{ new FullTextIndexEventListener() } );
-
- //slave(s)
- cfg[1].setProperty( "hibernate.search.default.sourceBase", "./lucenedirs/master/copy");
- cfg[1].setProperty( "hibernate.search.default.indexBase", "./lucenedirs/slave");
- cfg[1].setProperty( "hibernate.search.default.refresh", "1"); //every minute
- cfg[1].setProperty( "hibernate.search.default.directory_provider", "org.hibernate.search.store.FSSwitchableDirectoryProvider");
- cfg[1].getEventListeners().setPostDeleteEventListeners( new PostDeleteEventListener[]{ new FullTextIndexEventListener() } );
- cfg[1].getEventListeners().setPostUpdateEventListeners( new PostUpdateEventListener[]{ new FullTextIndexEventListener() } );
- cfg[1].getEventListeners().setPostInsertEventListeners( new PostInsertEventListener[]{ new FullTextIndexEventListener() } );
- }
-}
Modified: branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/AsyncWorkerTest.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/AsyncWorkerTest.java 2007-03-06 05:19:39 UTC (rev 11252)
+++ branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/AsyncWorkerTest.java 2007-03-06 05:23:23 UTC (rev 11253)
@@ -3,11 +3,7 @@
import org.hibernate.search.store.RAMDirectoryProvider;
import org.hibernate.search.Environment;
-import org.hibernate.search.event.FullTextIndexEventListener;
import org.hibernate.cfg.Configuration;
-import org.hibernate.event.PostDeleteEventListener;
-import org.hibernate.event.PostUpdateEventListener;
-import org.hibernate.event.PostInsertEventListener;
import org.apache.lucene.analysis.StopAnalyzer;
/**
@@ -19,9 +15,9 @@
cfg.setProperty( "hibernate.search.default.directory_provider", RAMDirectoryProvider.class.getName() );
cfg.setProperty( Environment.ANALYZER_CLASS, StopAnalyzer.class.getName() );
cfg.setProperty( Environment.WORKER_SCOPE, "transaction" );
- cfg.setProperty( Environment.WORKER_PROCESS, "async" );
- cfg.setProperty( Environment.WORKER_PREFIX + "thread_pool.min", "1" );
- cfg.setProperty( Environment.WORKER_PREFIX + "thread_pool.max", "10" );
+ cfg.setProperty( Environment.WORKER_EXECUTION, "async" );
+ cfg.setProperty( Environment.WORKER_PREFIX + "thread_pool.size", "1" );
+ cfg.setProperty( Environment.WORKER_PREFIX + "buffer_queue.max", "10" );
}
}
18 years, 6 months
Hibernate SVN: r11252 - branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/bridge/builtin.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-03-06 00:19:39 -0500 (Tue, 06 Mar 2007)
New Revision: 11252
Modified:
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/bridge/builtin/EnumBridge.java
Log:
minor
Modified: branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/bridge/builtin/EnumBridge.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/bridge/builtin/EnumBridge.java 2007-03-02 08:26:10 UTC (rev 11251)
+++ branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/bridge/builtin/EnumBridge.java 2007-03-06 05:19:39 UTC (rev 11252)
@@ -26,7 +26,7 @@
public String objectToString(Object object) {
Enum e = (Enum) object;
- return e.name();
+ return e != null ? e.name() : null;
}
}
18 years, 6 months
Hibernate SVN: r11251 - in branches/Branch_3_2/HibernateExt: annotations/src/java/org/hibernate/cfg and 11 other directories.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-03-02 03:26:10 -0500 (Fri, 02 Mar 2007)
New Revision: 11251
Modified:
branches/Branch_3_2/HibernateExt/annotations/doc/reference/en/modules/additionalmodules.xml
branches/Branch_3_2/HibernateExt/annotations/src/java/org/hibernate/cfg/AnnotationConfiguration.java
branches/Branch_3_2/HibernateExt/entitymanager/src/java/org/hibernate/ejb/EventListenerConfigurator.java
branches/Branch_3_2/HibernateExt/entitymanager/src/test/org/hibernate/ejb/test/PackagedEntityManagerTest.java
branches/Branch_3_2/HibernateExt/entitymanager/src/test/org/hibernate/ejb/test/ejb3configuration/EventOverridingTest.java
branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/configuration.xml
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/Environment.java
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/event/FullTextIndexEventListener.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/FSDirectoryTest.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/SearchTestCase.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/AsyncWorkerTest.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/SyncWorkerTest.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/WorkerTestCase.java
branches/Branch_3_2/HibernateExt/validator/doc/reference/en/modules/checkconstraints.xml
branches/Branch_3_2/HibernateExt/validator/src/java/org/hibernate/validator/Environment.java
branches/Branch_3_2/HibernateExt/validator/src/test/org/hibernate/validator/test/haintegration/HibernateAnnotationIntegrationTest.java
branches/Branch_3_2/HibernateExt/validator/src/test/org/hibernate/validator/test/haintegration/NonHibernateAnnotationsIntegrationTest.java
Log:
ANN-552 Transparent event registration if validator or search are in the classpath
Modified: branches/Branch_3_2/HibernateExt/annotations/doc/reference/en/modules/additionalmodules.xml
===================================================================
--- branches/Branch_3_2/HibernateExt/annotations/doc/reference/en/modules/additionalmodules.xml 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/annotations/doc/reference/en/modules/additionalmodules.xml 2007-03-02 08:26:10 UTC (rev 11251)
@@ -50,7 +50,7 @@
<para>If Hibernate Validator
(<filename>hibernate-validator.jar</filename>) is available in the
- classpath, Hibernate Annotations will integrates in two ways: </para>
+ classpath, Hibernate Annotations will integrates in two ways:</para>
<itemizedlist>
<listitem>
@@ -74,6 +74,14 @@
<literal>hibernate.validator.apply_to_ddl</literal> to false in the
configuration file. Such a need is very uncommon and not
recommanded.</para>
+
+ <para>To disable pre-entity change validation, set up
+ <literal>hibernate.validator.autoregister_listeners</literal> to false
+ in the configuration file. Such a need is very uncommon and not
+ recommanded.</para>
+
+ <para>Check the Hibernate Validator reference documentation for more
+ information.</para>
</section>
</section>
@@ -98,9 +106,15 @@
<section>
<title>Integration with Hibernate Annotations</title>
- <para>Hibernate Search integrates with Hibernate Annotations through
- Hibernate event listeners definitions, please check the Hibernate Search
- reference documentation for more information.</para>
+ <para>Hibernate Search integrates with Hibernate Annotations
+ transparently provided that hibernate-search.jar is present in the
+ classpath. If you do not wish to autoregister Hibernate Search event
+ listeners, you can set
+ <literal>hibernate.search.autoregister_listeners</literal> to false.
+ Such a need is very uncommon and not recommanded.</para>
+
+ <para>Check the Hibernate Search reference documentation for more
+ information.</para>
</section>
</section>
</chapter>
\ No newline at end of file
Modified: branches/Branch_3_2/HibernateExt/annotations/src/java/org/hibernate/cfg/AnnotationConfiguration.java
===================================================================
--- branches/Branch_3_2/HibernateExt/annotations/src/java/org/hibernate/cfg/AnnotationConfiguration.java 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/annotations/src/java/org/hibernate/cfg/AnnotationConfiguration.java 2007-03-02 08:26:10 UTC (rev 11251)
@@ -4,6 +4,8 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
@@ -13,15 +15,11 @@
import java.util.List;
import java.util.Map;
import java.util.Properties;
+import java.util.ResourceBundle;
import java.util.Set;
import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.TreeSet;
-import java.util.ResourceBundle;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
-
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
@@ -34,16 +32,23 @@
import org.dom4j.io.SAXReader;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
import org.hibernate.MappingException;
+import org.hibernate.SessionFactory;
+import org.hibernate.annotations.common.reflection.ReflectionManager;
+import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.cfg.annotations.Version;
+import org.hibernate.cfg.annotations.reflection.EJB3ReflectionManager;
+import org.hibernate.event.PreInsertEventListener;
+import org.hibernate.event.PreUpdateEventListener;
+import org.hibernate.event.PostInsertEventListener;
+import org.hibernate.event.PostUpdateEventListener;
+import org.hibernate.event.PostDeleteEventListener;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Join;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UniqueKey;
-import org.hibernate.annotations.common.reflection.ReflectionManager;
-import org.hibernate.annotations.common.reflection.XClass;
-import org.hibernate.cfg.annotations.reflection.EJB3ReflectionManager;
import org.hibernate.util.JoinedIterator;
import org.hibernate.util.ReflectHelper;
import org.hibernate.util.StringHelper;
@@ -739,6 +744,177 @@
}
}
+ public SessionFactory buildSessionFactory() throws HibernateException {
+ //add validator events if the jar is available
+ boolean enableValidatorListeners = ! "false".equalsIgnoreCase( getProperty( "hibernate.validator.autoregister_listeners" ) );
+ Class validateEventListenerClass = null;
+ try {
+ validateEventListenerClass = ReflectHelper.classForName(
+ "org.hibernate.validator.event.ValidateEventListener",
+ AnnotationConfiguration.class );
+ }
+ catch (ClassNotFoundException e) {
+ //validator is not present
+ log.debug( "Validator not present in classpath, ignoring event listener registration" );
+ }
+ if (enableValidatorListeners && validateEventListenerClass != null) {
+ //TODO so much duplication
+ Object validateEventListener;
+ try {
+ validateEventListener = validateEventListenerClass.newInstance();
+ }
+ catch (Exception e) {
+ throw new AnnotationException("Unable to load Validator event listener", e );
+ }
+ {
+ boolean present = false;
+ PreInsertEventListener[] listeners = getEventListeners().getPreInsertEventListeners();
+ if (listeners != null) {
+ for ( Object eventListener : listeners ) {
+ //not isAssignableFrom since the user could subclass
+ present = present || validateEventListenerClass == eventListener.getClass();
+ }
+ if (!present) {
+ int length = listeners.length + 1;
+ PreInsertEventListener[] newListeners = new PreInsertEventListener[length];
+ for ( int i = 0 ; i < length - 1 ; i++ ) {
+ newListeners[i] = listeners[i];
+ }
+ newListeners[length-1] = (PreInsertEventListener) validateEventListener;
+ getEventListeners().setPreInsertEventListeners(newListeners);
+ }
+ }
+ else {
+ getEventListeners().setPreInsertEventListeners(
+ new PreInsertEventListener[] { (PreInsertEventListener) validateEventListener }
+ );
+ }
+ }
+
+ //update event listener
+ {
+ boolean present = false;
+ PreUpdateEventListener[] listeners = getEventListeners().getPreUpdateEventListeners();
+ if (listeners != null) {
+ for ( Object eventListener : listeners ) {
+ //not isAssignableFrom since the user could subclass
+ present = present || validateEventListenerClass == eventListener.getClass();
+ }
+ if (!present) {
+ int length = listeners.length + 1;
+ PreUpdateEventListener[] newListeners = new PreUpdateEventListener[length];
+ for ( int i = 0 ; i < length - 1 ; i++ ) {
+ newListeners[i] = listeners[i];
+ }
+ newListeners[length-1] = (PreUpdateEventListener) validateEventListener;
+ getEventListeners().setPreUpdateEventListeners(newListeners);
+ }
+ }
+ else {
+ getEventListeners().setPreUpdateEventListeners(
+ new PreUpdateEventListener[] { (PreUpdateEventListener) validateEventListener }
+ );
+ }
+ }
+ }
+
+ //add search events if the jar is available
+ boolean enableSearchListeners = ! "false".equalsIgnoreCase( getProperty( "hibernate.search.autoregister_listeners" ) );
+ Class searchEventListenerClass = null;
+ try {
+ searchEventListenerClass = ReflectHelper.classForName(
+ "org.hibernate.search.event.FullTextIndexEventListener",
+ AnnotationConfiguration.class );
+ }
+ catch (ClassNotFoundException e) {
+ //search is not present
+ log.debug( "Search not present in classpath, ignoring event listener registration" );
+ }
+ if (enableSearchListeners && searchEventListenerClass != null) {
+ //TODO so much duplication
+ Object searchEventListener;
+ try {
+ searchEventListener = searchEventListenerClass.newInstance();
+ }
+ catch (Exception e) {
+ throw new AnnotationException("Unable to load Search event listener", e );
+ }
+ {
+ boolean present = false;
+ PostInsertEventListener[] listeners = getEventListeners().getPostInsertEventListeners();
+ if (listeners != null) {
+ for ( Object eventListener : listeners ) {
+ //not isAssignableFrom since the user could subclass
+ present = present || searchEventListenerClass == eventListener.getClass();
+ }
+ if (!present) {
+ int length = listeners.length + 1;
+ PostInsertEventListener[] newListeners = new PostInsertEventListener[length];
+ for ( int i = 0 ; i < length - 1 ; i++ ) {
+ newListeners[i] = listeners[i];
+ }
+ newListeners[length-1] = (PostInsertEventListener) searchEventListener;
+ getEventListeners().setPostInsertEventListeners(newListeners);
+ }
+ }
+ else {
+ getEventListeners().setPostInsertEventListeners(
+ new PostInsertEventListener[] { (PostInsertEventListener) searchEventListener }
+ );
+ }
+ }
+ {
+ boolean present = false;
+ PostUpdateEventListener[] listeners = getEventListeners().getPostUpdateEventListeners();
+ if (listeners != null) {
+ for ( Object eventListener : listeners ) {
+ //not isAssignableFrom since the user could subclass
+ present = present || searchEventListenerClass == eventListener.getClass();
+ }
+ if (!present) {
+ int length = listeners.length + 1;
+ PostUpdateEventListener[] newListeners = new PostUpdateEventListener[length];
+ for ( int i = 0 ; i < length - 1 ; i++ ) {
+ newListeners[i] = listeners[i];
+ }
+ newListeners[length-1] = (PostUpdateEventListener) searchEventListener;
+ getEventListeners().setPostUpdateEventListeners(newListeners);
+ }
+ }
+ else {
+ getEventListeners().setPostUpdateEventListeners(
+ new PostUpdateEventListener[] { (PostUpdateEventListener) searchEventListener }
+ );
+ }
+ }
+ {
+ boolean present = false;
+ PostDeleteEventListener[] listeners = getEventListeners().getPostDeleteEventListeners();
+ if (listeners != null) {
+ for ( Object eventListener : listeners ) {
+ //not isAssignableFrom since the user could subclass
+ present = present || searchEventListenerClass == eventListener.getClass();
+ }
+ if (!present) {
+ int length = listeners.length + 1;
+ PostDeleteEventListener[] newListeners = new PostDeleteEventListener[length];
+ for ( int i = 0 ; i < length - 1 ; i++ ) {
+ newListeners[i] = listeners[i];
+ }
+ newListeners[length-1] = (PostDeleteEventListener) searchEventListener;
+ getEventListeners().setPostDeleteEventListeners(newListeners);
+ }
+ }
+ else {
+ getEventListeners().setPostDeleteEventListeners(
+ new PostDeleteEventListener[] { (PostDeleteEventListener) searchEventListener }
+ );
+ }
+ }
+ }
+ return super.buildSessionFactory();
+ }
+
//not a public API
public ReflectionManager getReflectionManager() {
return reflectionManager;
Modified: branches/Branch_3_2/HibernateExt/entitymanager/src/java/org/hibernate/ejb/EventListenerConfigurator.java
===================================================================
--- branches/Branch_3_2/HibernateExt/entitymanager/src/java/org/hibernate/ejb/EventListenerConfigurator.java 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/entitymanager/src/java/org/hibernate/ejb/EventListenerConfigurator.java 2007-03-02 08:26:10 UTC (rev 11251)
@@ -65,7 +65,6 @@
public EventListenerConfigurator(Ejb3Configuration configuration) {
this.configuration = configuration;
- ValidateEventListener validateEventListener = new ValidateEventListener();
EventListeners listenerConfig = configuration.getEventListeners();
//Action event
@@ -91,13 +90,11 @@
listenerConfig.setPreInsertEventListeners(
new PreInsertEventListener[]{
new JACCPreInsertEventListener(),
- validateEventListener
}
);
listenerConfig.setPreUpdateEventListeners(
new PreUpdateEventListener[]{
new JACCPreUpdateEventListener(),
- validateEventListener
}
);
listenerConfig.setPreDeleteEventListeners(
Modified: branches/Branch_3_2/HibernateExt/entitymanager/src/test/org/hibernate/ejb/test/PackagedEntityManagerTest.java
===================================================================
--- branches/Branch_3_2/HibernateExt/entitymanager/src/test/org/hibernate/ejb/test/PackagedEntityManagerTest.java 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/entitymanager/src/test/org/hibernate/ejb/test/PackagedEntityManagerTest.java 2007-03-02 08:26:10 UTC (rev 11251)
@@ -214,29 +214,31 @@
emf.close();
}
- public void testListenersOverridingCfgXmlPar() throws Exception {
- EntityManagerFactory emf = Persistence.createEntityManagerFactory( "cfgxmlpar", new HashMap() );
- EntityManager em = emf.createEntityManager();
- Cat cat = new Cat();
- cat.setName( "123"); //validator catch that
- em.getTransaction().begin();
- try {
- em.persist( cat );
- em.flush();
- }
- catch (InvalidStateException e) {
- fail("Shouldn't call the ValidatorEvent listener");
- }
- catch (PersistenceException e) {
- if ( ! (e.getCause() instanceof JDBCException ) ) {
- fail("Unexpected exception: " + e);
- }
- }
- em.getTransaction().rollback();
- em.close();
- emf.close();
- }
+// This test does not make sense anymore, validator being autoregistered at the HAN level
+// public void testListenersOverridingCfgXmlPar() throws Exception {
+// EntityManagerFactory emf = Persistence.createEntityManagerFactory( "cfgxmlpar", new HashMap() );
+// EntityManager em = emf.createEntityManager();
+// Cat cat = new Cat();
+// cat.setName( "123"); //validator catch that
+// em.getTransaction().begin();
+// try {
+// em.persist( cat );
+// em.flush();
+// }
+// catch (InvalidStateException e) {
+// fail("Shouldn't call the ValidatorEvent listener");
+// }
+// catch (PersistenceException e) {
+// if ( ! (e.getCause() instanceof JDBCException ) ) {
+// fail("Unexpected exception: " + e);
+// }
+// }
+// em.getTransaction().rollback();
+//
+// em.close();
+// emf.close();
+// }
//EM TRANSACTION
// public void testEntityManager() {
Modified: branches/Branch_3_2/HibernateExt/entitymanager/src/test/org/hibernate/ejb/test/ejb3configuration/EventOverridingTest.java
===================================================================
--- branches/Branch_3_2/HibernateExt/entitymanager/src/test/org/hibernate/ejb/test/ejb3configuration/EventOverridingTest.java 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/entitymanager/src/test/org/hibernate/ejb/test/ejb3configuration/EventOverridingTest.java 2007-03-02 08:26:10 UTC (rev 11251)
@@ -7,8 +7,11 @@
import javax.persistence.Persistence;
import org.hibernate.ejb.test.Cat;
+import org.hibernate.ejb.HibernateEntityManagerFactory;
import org.hibernate.event.EventListeners;
import org.hibernate.event.PreInsertEventListener;
+import org.hibernate.Session;
+import org.hibernate.engine.SessionImplementor;
/**
* @author Emmanuel Bernard
@@ -17,41 +20,24 @@
public void testEventOverriding() throws Exception {
EventListeners eventListeners = configuration.getEventListeners();
- assertEquals( 2, eventListeners.getPreInsertEventListeners().length );
+ assertEquals( 1, eventListeners.getPreInsertEventListeners().length );
eventListeners.setPreInsertEventListeners( new PreInsertEventListener[]{} );
Cat cat = new Cat();
cat.setLength( 3 );
cat.setAge( 34 );
cat.setName( "Did" ); //should raise a validation exception
- EntityManager em = configuration.createEntityManagerFactory().createEntityManager();
- em.getTransaction().begin();
- try {
- em.persist( cat );
- }
- catch (Exception e) {
- fail( "The validation framework is still activated" );
- }
- em.flush();
- em.getTransaction().rollback();
+ EntityManagerFactory entityManagerFactory = configuration.createEntityManagerFactory();
+ EntityManager em = entityManagerFactory.createEntityManager();
+ assertEquals( "only validator should be present", 1,
+ ( (SessionImplementor) em.getDelegate() ).getListeners().getPreInsertEventListeners().length);
em.close();
}
public void testEventPerProperties() throws Exception {
EntityManagerFactory emf = Persistence.createEntityManagerFactory( "manager1", new HashMap() );
EntityManager em = emf.createEntityManager();
- em.getTransaction().begin();
- Cat cat = new Cat();
- cat.setLength( 3 );
- cat.setAge( 34 );
- cat.setName( "Did" ); //should raise a validation exception
- try {
- em.persist( cat );
- }
- catch (Exception e) {
- fail( "The validation framework is still activated" );
- }
- em.flush();
- em.getTransaction().rollback();
+ assertEquals( "Only validator should be present", 1,
+ ( (SessionImplementor) em.getDelegate() ).getListeners().getPreInsertEventListeners().length);
em.close();
emf.close();
}
Modified: branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/configuration.xml
===================================================================
--- branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/configuration.xml 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/configuration.xml 2007-03-02 08:26:10 UTC (rev 11251)
@@ -97,10 +97,17 @@
<section id="search-configuration-event" revision="1">
<title>Enabling automatic indexing</title>
- <para>Finally, we enable the <literal>SearchEventListener</literal> for
- the three Hibernate events that occur after changes are executed to the
- database.</para>
+ <para>Automatic indexing is enable out of the box when using Hibernate
+ Annotations or Hibernate EntityManager. If, for some reason you need to
+ disable that, set
+ <literal>hibernate.search.autoregister_listeners</literal> to false. Note
+ that there is no performance runtime when the listeners are enabled while
+ no entity is indexable.</para>
+ <para>To enable automatic indexing in Hibernate core, add the
+ <literal>SearchEventListener</literal> for the three Hibernate events that
+ occur after changes are executed to the database.</para>
+
<programlisting><hibernate-configuration>
...
<event type="post-update"
Modified: branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/Environment.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/Environment.java 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/Environment.java 2007-03-02 08:26:10 UTC (rev 11251)
@@ -6,6 +6,10 @@
*/
public final class Environment {
/**
+ * Enable listeners auto registration in Hibernate Annotations and EntityManager. Default to true.
+ */
+ public static final String AUTOREGISTER_LISTENERS = "hibernate.search.autoregister_listeners";
+ /**
* Indexes base directory
*/
public static final String INDEX_BASE_DIR = "hibernate.search.index_dir";
Modified: branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/event/FullTextIndexEventListener.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/event/FullTextIndexEventListener.java 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/event/FullTextIndexEventListener.java 2007-03-02 08:26:10 UTC (rev 11251)
@@ -36,11 +36,13 @@
PostUpdateEventListener, Initializable {
private static final Log log = LogFactory.getLog( FullTextIndexEventListener.class );
+ private boolean used;
private SearchFactory searchFactory;
public void initialize(Configuration cfg) {
searchFactory = SearchFactory.getSearchFactory( cfg );
+ used = searchFactory.getDocumentBuilders().size() != 0;
}
public SearchFactory getSearchFactory() {
@@ -48,31 +50,35 @@
}
public void onPostDelete(PostDeleteEvent event) {
- if ( searchFactory.getDocumentBuilders().containsKey( event.getEntity().getClass() ) ) {
+ if ( used && searchFactory.getDocumentBuilders().containsKey( event.getEntity().getClass() ) ) {
DeleteWork work = new DeleteWork( event.getId(), event.getEntity().getClass() );
processWork( work, event );
}
}
public void onPostInsert(PostInsertEvent event) {
- final Object entity = event.getEntity();
- DocumentBuilder<Object> builder = searchFactory.getDocumentBuilders().get( entity.getClass() );
- if ( builder != null ) {
- Serializable id = event.getId();
- Document doc = builder.getDocument( entity, id );
- AddWork work = new AddWork( id, entity.getClass(), doc );
- processWork( work, event );
+ if (used) {
+ final Object entity = event.getEntity();
+ DocumentBuilder<Object> builder = searchFactory.getDocumentBuilders().get( entity.getClass() );
+ if ( builder != null ) {
+ Serializable id = event.getId();
+ Document doc = builder.getDocument( entity, id );
+ AddWork work = new AddWork( id, entity.getClass(), doc );
+ processWork( work, event );
+ }
}
}
public void onPostUpdate(PostUpdateEvent event) {
- final Object entity = event.getEntity();
- DocumentBuilder<Object> builder = searchFactory.getDocumentBuilders().get( entity.getClass() );
- if ( builder != null ) {
- Serializable id = event.getId();
- Document doc = builder.getDocument( entity, id );
- UpdateWork work = new UpdateWork( id, entity.getClass(), doc );
- processWork( work, event );
+ if (used) {
+ final Object entity = event.getEntity();
+ DocumentBuilder<Object> builder = searchFactory.getDocumentBuilders().get( entity.getClass() );
+ if ( builder != null ) {
+ Serializable id = event.getId();
+ Document doc = builder.getDocument( entity, id );
+ UpdateWork work = new UpdateWork( id, entity.getClass(), doc );
+ processWork( work, event );
+ }
}
}
Modified: branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/FSDirectoryTest.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/FSDirectoryTest.java 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/FSDirectoryTest.java 2007-03-02 08:26:10 UTC (rev 11251)
@@ -18,8 +18,8 @@
import org.hibernate.event.PostInsertEventListener;
import org.hibernate.event.PostUpdateEventListener;
import org.hibernate.search.Environment;
+import org.hibernate.search.event.FullTextIndexEventListener;
import org.hibernate.search.store.FSDirectoryProvider;
-import org.hibernate.search.event.FullTextIndexEventListener;
/**
* @author Gavin King
Modified: branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/SearchTestCase.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/SearchTestCase.java 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/SearchTestCase.java 2007-03-02 08:26:10 UTC (rev 11251)
@@ -4,9 +4,7 @@
import org.apache.lucene.analysis.StopAnalyzer;
import org.apache.lucene.store.Directory;
import org.hibernate.HibernateException;
-import org.hibernate.event.PostDeleteEventListener;
import org.hibernate.event.PostInsertEventListener;
-import org.hibernate.event.PostUpdateEventListener;
import org.hibernate.impl.SessionFactoryImpl;
import org.hibernate.search.Environment;
import org.hibernate.search.event.FullTextIndexEventListener;
@@ -42,9 +40,5 @@
protected void configure(org.hibernate.cfg.Configuration cfg) {
cfg.setProperty( "hibernate.search.default.directory_provider", RAMDirectoryProvider.class.getName() );
cfg.setProperty( Environment.ANALYZER_CLASS, StopAnalyzer.class.getName() );
- //FullTextIndexEventListener del = new FullTextIndexEventListener();
- cfg.getEventListeners().setPostDeleteEventListeners( new PostDeleteEventListener[]{ new FullTextIndexEventListener() } );
- cfg.getEventListeners().setPostUpdateEventListeners( new PostUpdateEventListener[]{ new FullTextIndexEventListener() } );
- cfg.getEventListeners().setPostInsertEventListeners( new PostInsertEventListener[]{ new FullTextIndexEventListener() } );
}
}
Modified: branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/AsyncWorkerTest.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/AsyncWorkerTest.java 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/AsyncWorkerTest.java 2007-03-02 08:26:10 UTC (rev 11251)
@@ -22,10 +22,6 @@
cfg.setProperty( Environment.WORKER_PROCESS, "async" );
cfg.setProperty( Environment.WORKER_PREFIX + "thread_pool.min", "1" );
cfg.setProperty( Environment.WORKER_PREFIX + "thread_pool.max", "10" );
- FullTextIndexEventListener del = new FullTextIndexEventListener();
- cfg.getEventListeners().setPostDeleteEventListeners( new PostDeleteEventListener[]{del} );
- cfg.getEventListeners().setPostUpdateEventListeners( new PostUpdateEventListener[]{del} );
- cfg.getEventListeners().setPostInsertEventListeners( new PostInsertEventListener[]{del} );
}
}
Modified: branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/SyncWorkerTest.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/SyncWorkerTest.java 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/SyncWorkerTest.java 2007-03-02 08:26:10 UTC (rev 11251)
@@ -20,9 +20,5 @@
cfg.setProperty( Environment.ANALYZER_CLASS, StopAnalyzer.class.getName() );
cfg.setProperty( Environment.WORKER_SCOPE, "transaction" );
cfg.setProperty( Environment.WORKER_PREFIX, "sync" );
- FullTextIndexEventListener del = new FullTextIndexEventListener();
- cfg.getEventListeners().setPostDeleteEventListeners( new PostDeleteEventListener[]{del} );
- cfg.getEventListeners().setPostUpdateEventListeners( new PostUpdateEventListener[]{del} );
- cfg.getEventListeners().setPostInsertEventListeners( new PostInsertEventListener[]{del} );
}
}
Modified: branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/WorkerTestCase.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/WorkerTestCase.java 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/worker/WorkerTestCase.java 2007-03-02 08:26:10 UTC (rev 11251)
@@ -1,26 +1,26 @@
//$Id: $
package org.hibernate.search.test.worker;
+import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import java.io.File;
-import org.hibernate.search.test.SearchTestCase;
-import org.hibernate.search.store.FSDirectoryProvider;
-import org.hibernate.search.Environment;
-import org.hibernate.search.FullTextSession;
-import org.hibernate.search.impl.FullTextSessionImpl;
-import org.hibernate.search.event.FullTextIndexEventListener;
+import org.apache.lucene.analysis.StopAnalyzer;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.search.Query;
+import org.hibernate.Session;
import org.hibernate.SessionFactory;
-import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.event.PostDeleteEventListener;
+import org.hibernate.event.PostInsertEventListener;
import org.hibernate.event.PostUpdateEventListener;
-import org.hibernate.event.PostInsertEventListener;
-import org.apache.lucene.analysis.StopAnalyzer;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.queryParser.QueryParser;
-import org.apache.lucene.queryParser.ParseException;
+import org.hibernate.search.Environment;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.event.FullTextIndexEventListener;
+import org.hibernate.search.impl.FullTextSessionImpl;
+import org.hibernate.search.store.FSDirectoryProvider;
+import org.hibernate.search.test.SearchTestCase;
/**
* @author Emmanuel Bernard
Modified: branches/Branch_3_2/HibernateExt/validator/doc/reference/en/modules/checkconstraints.xml
===================================================================
--- branches/Branch_3_2/HibernateExt/validator/doc/reference/en/modules/checkconstraints.xml 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/validator/doc/reference/en/modules/checkconstraints.xml 2007-03-02 08:26:10 UTC (rev 11251)
@@ -48,6 +48,21 @@
contains an array of <literal>InvalidValue</literal>s describing each
failure.</para>
+ <para>If Hibernate Validator is present in the classpath, Hibernate
+ Annotations (or Hibernate EntityManager) will use it transparently. If,
+ for some reason, you want to disable this integration, set
+ <literal>hibernate.validator.autoregister_listeners</literal> to
+ false</para>
+
+ <para><note>
+ <para>If the beans are not annotated with validation annotations,
+ there is no runtime performance cost.</para>
+ </note></para>
+
+ <para>In case you need to manually set the event listeners for Hibernate
+ Core, use the following configuration in
+ <literal>hibernate.cfg.xml</literal>:</para>
+
<programlisting><hibernate-configuration>
...
<event type="pre-update">
@@ -59,12 +74,6 @@
class="org.hibernate.validator.event.ValidateEventListener"/>
</event>
</hibernate-configuration></programlisting>
-
- <para><note>
- <para>When using Hibernate Entity Manager, the Validation framework
- is activated out of the box. If the beans are not annotated with
- validation annotations, there is no performance cost.</para>
- </note></para>
</section>
<section id="validator-checkconstraints-orm-jpaevent">
Modified: branches/Branch_3_2/HibernateExt/validator/src/java/org/hibernate/validator/Environment.java
===================================================================
--- branches/Branch_3_2/HibernateExt/validator/src/java/org/hibernate/validator/Environment.java 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/validator/src/java/org/hibernate/validator/Environment.java 2007-03-02 08:26:10 UTC (rev 11251)
@@ -15,7 +15,12 @@
public static final String MESSAGE_INTERPOLATOR_CLASS = "hibernate.validator.message_interpolator_class";
/**
- * Apply DDL changes on Hibernate metamodel when using validator with Hibernate Annotations
+ * Apply DDL changes on Hibernate metamodel when using validator with Hibernate Annotations. Default to true.
*/
public static final String APPLY_TO_DDL = "hibernate.validator.apply_to_ddl";
+
+ /**
+ * Enable listeners auto registration in Hibernate Annotations and EntityManager. Default to true.
+ */
+ public static final String AUTOREGISTER_LISTENERS = "hibernate.validator.autoregister_listeners";
}
Modified: branches/Branch_3_2/HibernateExt/validator/src/test/org/hibernate/validator/test/haintegration/HibernateAnnotationIntegrationTest.java
===================================================================
--- branches/Branch_3_2/HibernateExt/validator/src/test/org/hibernate/validator/test/haintegration/HibernateAnnotationIntegrationTest.java 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/validator/src/test/org/hibernate/validator/test/haintegration/HibernateAnnotationIntegrationTest.java 2007-03-02 08:26:10 UTC (rev 11251)
@@ -149,10 +149,6 @@
protected void configure(Configuration cfg) {
cfg.setProperty( Environment.MESSAGE_INTERPOLATOR_CLASS, PrefixMessageInterpolator.class.getName() );
- cfg.getEventListeners()
- .setPreInsertEventListeners( new PreInsertEventListener[]{new ValidateEventListener()} );
- cfg.getEventListeners()
- .setPreUpdateEventListeners( new PreUpdateEventListener[]{new ValidateEventListener()} );
}
protected Class[] getMappings() {
Modified: branches/Branch_3_2/HibernateExt/validator/src/test/org/hibernate/validator/test/haintegration/NonHibernateAnnotationsIntegrationTest.java
===================================================================
--- branches/Branch_3_2/HibernateExt/validator/src/test/org/hibernate/validator/test/haintegration/NonHibernateAnnotationsIntegrationTest.java 2007-03-01 17:52:59 UTC (rev 11250)
+++ branches/Branch_3_2/HibernateExt/validator/src/test/org/hibernate/validator/test/haintegration/NonHibernateAnnotationsIntegrationTest.java 2007-03-02 08:26:10 UTC (rev 11251)
@@ -9,6 +9,7 @@
import org.hibernate.validator.Environment;
import org.hibernate.validator.test.HANTestCase;
import org.hibernate.validator.event.ValidateEventListener;
+import org.hibernate.Session;
/**
* Test the ability to disable DDL update
@@ -16,9 +17,8 @@
* @author Emmanuel Bernard
*/
public class NonHibernateAnnotationsIntegrationTest extends HANTestCase {
- public void testNotApply() throws Exception {
+ public void testNotApplyDll() throws Exception {
PersistentClass classMapping = getCfg().getClassMapping( Address.class.getName() );
- //new ClassValidator( Address.class, ResourceBundle.getBundle("messages", Locale.ENGLISH) ).apply( classMapping );
Column stateColumn = (Column) classMapping.getProperty( "state" ).getColumnIterator().next();
assertFalse( stateColumn.getLength() == 3 );
Column zipColumn = (Column) classMapping.getProperty( "zip" ).getColumnIterator().next();
@@ -26,13 +26,18 @@
assertTrue( zipColumn.isNullable() );
}
+ public void testNotApplyListener() throws Exception {
+ Session s = openSession( );
+ Address a = new Address();
+ s.persist( a ); //shouldn't fail
+ s.flush();
+ s.close();
+ }
+
protected void configure(Configuration cfg) {
cfg.setProperty( Environment.MESSAGE_INTERPOLATOR_CLASS, PrefixMessageInterpolator.class.getName() );
cfg.setProperty( Environment.APPLY_TO_DDL, "false" );
- cfg.getEventListeners()
- .setPreInsertEventListeners( new PreInsertEventListener[]{new ValidateEventListener()} );
- cfg.getEventListeners()
- .setPreUpdateEventListeners( new PreUpdateEventListener[]{new ValidateEventListener()} );
+ cfg.setProperty( Environment.AUTOREGISTER_LISTENERS, "false" );
}
protected Class[] getMappings() {
18 years, 6 months
Hibernate SVN: r11250 - branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/impl.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-03-01 12:52:59 -0500 (Thu, 01 Mar 2007)
New Revision: 11250
Modified:
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/impl/FullTextSessionImpl.java
Log:
HSEARCH-25 never cast to SessionImpl since Hibernate wrap the session sometimes. Bad me
Modified: branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/impl/FullTextSessionImpl.java
===================================================================
--- branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/impl/FullTextSessionImpl.java 2007-03-01 08:29:34 UTC (rev 11249)
+++ branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/impl/FullTextSessionImpl.java 2007-03-01 17:52:59 UTC (rev 11250)
@@ -7,55 +7,48 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Properties;
-import javax.transaction.Status;
-
+import org.apache.lucene.document.Document;
import org.hibernate.CacheMode;
import org.hibernate.Criteria;
import org.hibernate.EntityMode;
import org.hibernate.Filter;
import org.hibernate.FlushMode;
+import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.ReplicationMode;
import org.hibernate.SQLQuery;
-import org.hibernate.Session;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.classic.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
-import org.hibernate.Interceptor;
-import org.hibernate.ScrollableResults;
-import org.hibernate.ScrollMode;
-import org.hibernate.Hibernate;
-import org.hibernate.event.EventListeners;
-import org.hibernate.loader.custom.CustomQuery;
-import org.hibernate.persister.entity.EntityPersister;
-import org.hibernate.jdbc.Batcher;
-import org.hibernate.jdbc.JDBCContext;
import org.hibernate.collection.PersistentCollection;
-import org.hibernate.engine.query.ParameterMetadata;
-import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
-import org.hibernate.engine.SessionImplementor;
-import org.hibernate.engine.SessionFactoryImplementor;
-import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.EntityKey;
import org.hibernate.engine.PersistenceContext;
-import org.hibernate.impl.SessionImpl;
+import org.hibernate.engine.QueryParameters;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.query.ParameterMetadata;
+import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
+import org.hibernate.event.EventListeners;
+import org.hibernate.event.EventSource;
import org.hibernate.impl.CriteriaImpl;
-import org.hibernate.search.query.FullTextQueryImpl;
-import org.hibernate.search.util.ContextHelper;
-import org.hibernate.search.engine.DocumentBuilder;
+import org.hibernate.jdbc.Batcher;
+import org.hibernate.jdbc.JDBCContext;
+import org.hibernate.loader.custom.CustomQuery;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.search.FullTextSession;
import org.hibernate.search.SearchFactory;
import org.hibernate.search.backend.UpdateWork;
-import org.hibernate.search.backend.Work;
-import org.hibernate.search.backend.QueueingProcessor;
-import org.hibernate.search.backend.impl.BatchedQueueingProcessor;
-import org.hibernate.search.backend.impl.PostTransactionWorkQueueSynchronization;
-import org.hibernate.search.FullTextSession;
+import org.hibernate.search.engine.DocumentBuilder;
+import org.hibernate.search.query.FullTextQueryImpl;
+import org.hibernate.search.util.ContextHelper;
import org.hibernate.stat.SessionStatistics;
import org.hibernate.type.Type;
-import org.apache.lucene.document.Document;
/**
* Lucene Full text search aware session
@@ -63,11 +56,14 @@
* @author Emmanuel Bernard
*/
public class FullTextSessionImpl implements FullTextSession, SessionImplementor {
- private final SessionImpl session;
- private PostTransactionWorkQueueSynchronization postTransactionWorkQueueSynch;
+ private final Session session;
+ private final EventSource eventSource;
+ private final SessionImplementor sessionImplementor;
- public FullTextSessionImpl(Session session) {
- this.session = (SessionImpl) session;
+ public FullTextSessionImpl(org.hibernate.Session session) {
+ this.session = (Session) session;
+ this.eventSource = (EventSource) session;
+ this.sessionImplementor = (SessionImplementor) session;
}
/**
@@ -77,7 +73,7 @@
* @param entities must be immutable for the lifetime of the query object
*/
public Query createFullTextQuery(org.apache.lucene.search.Query luceneQuery, Class... entities) {
- return new FullTextQueryImpl( luceneQuery, entities, session, new ParameterMetadata(null, null) );
+ return new FullTextQueryImpl( luceneQuery, entities, sessionImplementor, new ParameterMetadata(null, null) );
}
/**
@@ -96,7 +92,7 @@
Serializable id = session.getIdentifier( entity );
Document doc = builder.getDocument( entity, id );
UpdateWork work = new UpdateWork( id, entity.getClass(), doc );
- searchFactory.getWorker().performWork( work, session );
+ searchFactory.getWorker().performWork( work, eventSource );
}
//TODO
//need to add elements in a queue kept at the Session level
@@ -204,9 +200,7 @@
}
public void clear() {
- if (postTransactionWorkQueueSynch != null && !postTransactionWorkQueueSynch.isConsumed() ) {
- postTransactionWorkQueueSynch.afterCompletion( Status.STATUS_ROLLEDBACK );
- }
+ //FIXME should session clear work with the lucene queue
session.clear();
}
@@ -307,153 +301,153 @@
}
public Interceptor getInterceptor() {
- return session.getInterceptor();
+ return sessionImplementor.getInterceptor();
}
public void setAutoClear(boolean enabled) {
- session.setAutoClear( enabled );
+ sessionImplementor.setAutoClear( enabled );
}
public boolean isTransactionInProgress() {
- return session.isTransactionInProgress();
+ return sessionImplementor.isTransactionInProgress();
}
public void initializeCollection(PersistentCollection collection, boolean writing) throws HibernateException {
- session.initializeCollection( collection, writing );
+ sessionImplementor.initializeCollection( collection, writing );
}
public Object internalLoad(String entityName, Serializable id, boolean eager, boolean nullable)
throws HibernateException {
- return session.internalLoad( entityName, id, eager, nullable );
+ return sessionImplementor.internalLoad( entityName, id, eager, nullable );
}
public Object immediateLoad(String entityName, Serializable id) throws HibernateException {
- return session.immediateLoad( entityName, id );
+ return sessionImplementor.immediateLoad( entityName, id );
}
public long getTimestamp() {
- return session.getTimestamp();
+ return sessionImplementor.getTimestamp();
}
public SessionFactoryImplementor getFactory() {
- return session.getFactory();
+ return sessionImplementor.getFactory();
}
public Batcher getBatcher() {
- return session.getBatcher();
+ return sessionImplementor.getBatcher();
}
public List list(String query, QueryParameters queryParameters) throws HibernateException {
- return session.list( query, queryParameters );
+ return sessionImplementor.list( query, queryParameters );
}
public Iterator iterate(String query, QueryParameters queryParameters) throws HibernateException {
- return session.iterate( query, queryParameters );
+ return sessionImplementor.iterate( query, queryParameters );
}
public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException {
- return session.scroll( query, queryParameters );
+ return sessionImplementor.scroll( query, queryParameters );
}
public ScrollableResults scroll(CriteriaImpl criteria, ScrollMode scrollMode) {
- return session.scroll( criteria, scrollMode );
+ return sessionImplementor.scroll( criteria, scrollMode );
}
public List list(CriteriaImpl criteria) {
- return session.list( criteria );
+ return sessionImplementor.list( criteria );
}
public List listFilter(Object collection, String filter, QueryParameters queryParameters)
throws HibernateException {
- return session.listFilter( collection, filter, queryParameters );
+ return sessionImplementor.listFilter( collection, filter, queryParameters );
}
public Iterator iterateFilter(Object collection, String filter, QueryParameters queryParameters)
throws HibernateException {
- return session.iterateFilter( collection, filter, queryParameters );
+ return sessionImplementor.iterateFilter( collection, filter, queryParameters );
}
public EntityPersister getEntityPersister(String entityName, Object object) throws HibernateException {
- return session.getEntityPersister( entityName, object );
+ return sessionImplementor.getEntityPersister( entityName, object );
}
public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException {
- return session.getEntityUsingInterceptor( key );
+ return sessionImplementor.getEntityUsingInterceptor( key );
}
public void afterTransactionCompletion(boolean successful, Transaction tx) {
- session.afterTransactionCompletion( successful, tx );
+ sessionImplementor.afterTransactionCompletion( successful, tx );
}
public void beforeTransactionCompletion(Transaction tx) {
- session.beforeTransactionCompletion( tx );
+ sessionImplementor.beforeTransactionCompletion( tx );
}
public Serializable getContextEntityIdentifier(Object object) {
- return session.getContextEntityIdentifier( object );
+ return sessionImplementor.getContextEntityIdentifier( object );
}
public String bestGuessEntityName(Object object) {
- return session.bestGuessEntityName( object );
+ return sessionImplementor.bestGuessEntityName( object );
}
public String guessEntityName(Object entity) throws HibernateException {
- return session.guessEntityName( entity );
+ return sessionImplementor.guessEntityName( entity );
}
public Object instantiate(String entityName, Serializable id) throws HibernateException {
- return session.instantiate( entityName, id );
+ return sessionImplementor.instantiate( entityName, id );
}
public List listCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) throws HibernateException {
- return session.listCustomQuery( customQuery, queryParameters );
+ return sessionImplementor.listCustomQuery( customQuery, queryParameters );
}
public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters)
throws HibernateException {
- return session.scrollCustomQuery( customQuery, queryParameters );
+ return sessionImplementor.scrollCustomQuery( customQuery, queryParameters );
}
public List list(NativeSQLQuerySpecification spec, QueryParameters queryParameters) throws HibernateException {
- return session.list( spec, queryParameters );
+ return sessionImplementor.list( spec, queryParameters );
}
public ScrollableResults scroll(NativeSQLQuerySpecification spec, QueryParameters queryParameters)
throws HibernateException {
- return session.scroll( spec, queryParameters );
+ return sessionImplementor.scroll( spec, queryParameters );
}
public Object getFilterParameterValue(String filterParameterName) {
- return session.getFilterParameterValue( filterParameterName );
+ return sessionImplementor.getFilterParameterValue( filterParameterName );
}
public Type getFilterParameterType(String filterParameterName) {
- return session.getFilterParameterType( filterParameterName );
+ return sessionImplementor.getFilterParameterType( filterParameterName );
}
public Map getEnabledFilters() {
- return session.getEnabledFilters();
+ return sessionImplementor.getEnabledFilters();
}
public int getDontFlushFromFind() {
- return session.getDontFlushFromFind();
+ return sessionImplementor.getDontFlushFromFind();
}
public EventListeners getListeners() {
- return session.getListeners();
+ return sessionImplementor.getListeners();
}
public PersistenceContext getPersistenceContext() {
- return session.getPersistenceContext();
+ return sessionImplementor.getPersistenceContext();
}
public int executeUpdate(String query, QueryParameters queryParameters) throws HibernateException {
- return session.executeUpdate( query, queryParameters );
+ return sessionImplementor.executeUpdate( query, queryParameters );
}
public int executeNativeUpdate(NativeSQLQuerySpecification specification, QueryParameters queryParameters)
throws HibernateException {
- return session.executeNativeUpdate( specification, queryParameters );
+ return sessionImplementor.executeNativeUpdate( specification, queryParameters );
}
public EntityMode getEntityMode() {
@@ -477,31 +471,31 @@
}
public Query getNamedSQLQuery(String name) {
- return session.getNamedSQLQuery( name );
+ return sessionImplementor.getNamedSQLQuery( name );
}
public boolean isEventSource() {
- return session.isEventSource();
+ return sessionImplementor.isEventSource();
}
public void afterScrollOperation() {
- session.afterScrollOperation();
+ sessionImplementor.afterScrollOperation();
}
public void setFetchProfile(String name) {
- session.setFetchProfile( name );
+ sessionImplementor.setFetchProfile( name );
}
public String getFetchProfile() {
- return session.getFetchProfile();
+ return sessionImplementor.getFetchProfile();
}
public JDBCContext getJDBCContext() {
- return session.getJDBCContext();
+ return sessionImplementor.getJDBCContext();
}
public boolean isClosed() {
- return session.isClosed();
+ return sessionImplementor.isClosed();
}
public org.hibernate.Session getSession(EntityMode entityMode) {
18 years, 6 months
Hibernate SVN: r11249 - in branches/Branch_3_2/HibernateExt: annotations/src/java/org/hibernate/annotations and 2 other directories.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-03-01 03:29:34 -0500 (Thu, 01 Mar 2007)
New Revision: 11249
Modified:
branches/Branch_3_2/HibernateExt/annotations/doc/reference/en/modules/entity.xml
branches/Branch_3_2/HibernateExt/annotations/doc/reference/en/modules/setup.xml
branches/Branch_3_2/HibernateExt/annotations/src/java/org/hibernate/annotations/Table.java
branches/Branch_3_2/HibernateExt/annotations/src/java/org/hibernate/annotations/Tuplizer.java
branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/architecture.xml
branches/Branch_3_2/HibernateExt/validator/doc/reference/en/modules/checkconstraints.xml
branches/Branch_3_2/HibernateExt/validator/doc/reference/en/modules/defineconstraints.xml
Log:
Documentation
Modified: branches/Branch_3_2/HibernateExt/annotations/doc/reference/en/modules/entity.xml
===================================================================
--- branches/Branch_3_2/HibernateExt/annotations/doc/reference/en/modules/entity.xml 2007-02-28 02:06:13 UTC (rev 11248)
+++ branches/Branch_3_2/HibernateExt/annotations/doc/reference/en/modules/entity.xml 2007-03-01 08:29:34 UTC (rev 11249)
@@ -133,8 +133,8 @@
type provided that you define and implement the appropriate
<classname>UserVersionType</classname>.</para>
- <para>The application must not alter the version number set up
- by Hibernate in any way. To artificially increase the version number,
+ <para>The application must not alter the version number set up by
+ Hibernate in any way. To artificially increase the version number,
check in Hibernate Entity Manager's reference documentation
<literal>LockMode.WRITE</literal></para>
</sect3>
@@ -2238,7 +2238,7 @@
<classname>org.hibernate.annotations</classname> package contains all
these annotations extensions.</para>
- <sect2 id="entity-hibspec-entity" revision="2">
+ <sect2 id="entity-hibspec-entity" revision="3">
<title>Entity</title>
<para>You can fine tune some of the actions done by Hibernate on
@@ -2323,6 +2323,45 @@
<literal>@org.hibernate.annotations.Table</literal>.</para>
</note>
+ <para><literal>@org.hibernate.annotations.Table</literal> can also be
+ used to define the following elements of secondary tables: </para>
+
+ <itemizedlist>
+ <listitem>
+ <para><literal>fetch</literal>: If set to JOIN, the default,
+ Hibernate will use an inner join to retrieve a secondary table
+ defined by a class or its superclasses and an outer join for a
+ secondary table defined by a subclass. If set to select then
+ Hibernate will use a sequential select for a secondary table defined
+ on a subclass, which will be issued only if a row turns out to
+ represent an instance of the subclass. Inner joins will still be
+ used to retrieve a secondary defined by the class and its
+ superclasses.</para>
+ </listitem>
+
+ <listitem>
+ <para><literal>inverse</literal>: If true, Hibernate will not try to
+ insert or update the properties defined by this join. Default to
+ false.</para>
+ </listitem>
+
+ <listitem>
+ <para><literal>optional</literal>: If enabled (the default),
+ Hibernate will insert a row only if the properties defined by this
+ join are non-null and will always use an outer join to retrieve the
+ properties. </para>
+ </listitem>
+
+ <listitem>
+ <para><literal>foreignKey</literal>: defines the Foreign Key name of
+ a secondary table pointing back to the primary table.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para><literal>@Immutable</literal> marks an entity as immutable. The
+ entity may not be updated or deleted by the application. This allows
+ Hibernate to make some minor performance optimizations.</para>
+
<para><programlisting>@Entity
@BatchSize(size=5)
@org.hibernate.annotations.Entity(
@@ -2648,7 +2687,7 @@
</sect3>
</sect2>
- <sect2 id="entity-hibspec-inheritance" revision="1">
+ <sect2 id="entity-hibspec-inheritance" revision="2">
<title>Inheritance</title>
<para>SINGLE_TABLE is a very powerful strategy but sometimes, and
@@ -2661,7 +2700,7 @@
column).</para>
<programlisting>@Entity
-@DiscriminatorForumla("case when forest_type is null then 0 else forest_type end")
+<emphasis role="bold">@DiscriminatorForumla("case when forest_type is null then 0 else forest_type end")</emphasis>
public class Forest { ... }</programlisting>
<para>By default, when querying the top entities, Hibernate does not put
@@ -2671,6 +2710,21 @@
you can use <literal>@ForceDiscriminator</literal> (at the class level,
next to <literal>@DiscriminatorColumn</literal>). Hibernate will then
list the available values when loading the entities.</para>
+
+ <para>You can define the foreign key name generated by Hibernate for
+ subclass tables in the JOINED inheritance strategy.</para>
+
+ <programlisting>@Entity
+@Inheritance(strategy = InheritanceType.JOINED)
+public abstract class File { ... }
+
+@Entity
+@ForeignKey(name = "FK_DOCU_FILE")
+public class Document extends File {</programlisting>
+
+ <para>The foreign key from the <literal>Document</literal> table to the
+ <literal>File</literal> table will be named
+ <literal>FK_DOCU_FILE</literal>.</para>
</sect2>
<sect2 id="entity-hibspec-singleassoc">
@@ -2830,7 +2884,7 @@
<sect2 id="entity-hibspec-collection" revision="2">
<title>Collection related annotations</title>
- <sect3 id="entity-hibspec-collection-enhance" revision="2">
+ <sect3 id="entity-hibspec-collection-enhance" revision="3">
<title>Enhance collection settings</title>
<para>It is possible to set <itemizedlist>
@@ -2853,6 +2907,10 @@
<listitem>
the delete cascade strategy through @OnDelete(action=OnDeleteAction.CASCADE)
</listitem>
+
+ <listitem>
+ the collection immutability using @Immutable: if set specifies that the elements of the collection never change (a minor performance optimization in some cases)
+ </listitem>
</itemizedlist></para>
<para>You can also declare a sort comparator. Use the
@@ -3355,8 +3413,8 @@
ability to set those annotations at a package level.</para>
</sect2>
- <sect2 id="entity-hibspec-customsql">
- <title>Custom SQL for CRUD operations</title>
+ <sect2 id="entity-hibspec-customsql" revision="1">
+ <title> Custom SQL for CRUD operations</title>
<para>Hibernate gives you the avility to override every single SQL
statement generated. We have seen native SQL query usage already, but
@@ -3432,6 +3490,69 @@
expected sequence, remember to not include your custom SQL through
annotations as that will override the Hibernate generated static
sql.)</para>
+
+ <para>Overriding SQL statements for secondary tables is also possible
+ using <literal>@org.hibernate.annotations.Table</literal> and either (or
+ all) attributes <literal>sqlInsert</literal>,
+ <literal>sqlUpdate</literal>, <literal>sqlDelete</literal>:</para>
+
+ <programlisting>@Entity
+@SecondaryTables({
+ @SecondaryTable(name = "`Cat nbr1`"),
+ @SecondaryTable(name = "Cat2"})
+(a)org.hibernate.annotations.Tables( {
+ @Table(appliesTo = "Cat", comment = "My cat table" ),
+ @Table(appliesTo = "Cat2", foreignKey = @ForeignKey(name="FK_CAT2_CAT"), fetch = FetchMode.SELECT,
+ <emphasis role="bold">sqlInsert=@SQLInsert(sql="insert into Cat2(storyPart2, id) values(upper(?), ?)") )</emphasis>
+} )
+public class Cat implements Serializable {</programlisting>
+
+ <para>The previous example also show that you can give a comment to a
+ given table (promary or secondary): This comment will be used for DDL
+ generation.</para>
</sect2>
+
+ <sect2>
+ <title>Tuplizer</title>
+
+ <para><classname>org.hibernate.tuple.Tuplizer</classname>, and its
+ sub-interfaces, are responsible for managing a particular representation
+ of a piece of data, given that representation's
+ <literal>org.hibernate.EntityMode</literal>. If a given piece of data is
+ thought of as a data structure, then a tuplizer is the thing which knows
+ how to create such a data structure and how to extract values from and
+ inject values into such a data structure. For example, for the POJO
+ entity mode, the correpsonding tuplizer knows how create the POJO
+ through its constructor and how to access the POJO properties using the
+ defined property accessors. There are two high-level types of Tuplizers,
+ represented by the
+ <classname>org.hibernate.tuple.EntityTuplizer</classname> and
+ <classname>org.hibernate.tuple.ComponentTuplizer</classname> interfaces.
+ EntityTuplizers are responsible for managing the above mentioned
+ contracts in regards to entities, while
+ <classname>ComponentTuplizers</classname> do the same for components.
+ Check the Hibernate reference documentation for more information.</para>
+
+ <para>To define tuplixer in annotations, simply use the
+ <literal>@Tuplizer</literal> annotation on the according element</para>
+
+ <programlisting>@Entity
+<emphasis role="bold">@Tuplizer(impl = DynamicEntityTuplizer.class)</emphasis>
+public interface Cuisine {
+ @Id
+ @GeneratedValue
+ public Long getId();
+ public void setId(Long id);
+
+ public String getName();
+ public void setName(String name);
+
+ <emphasis role="bold">@Tuplizer(impl = DynamicComponentTuplizer.class)</emphasis>
+ public Country getCountry();
+ public void setCountry(Country country);
+
+
+}</programlisting>
+ </sect2>
</sect1>
</chapter>
\ No newline at end of file
Modified: branches/Branch_3_2/HibernateExt/annotations/doc/reference/en/modules/setup.xml
===================================================================
--- branches/Branch_3_2/HibernateExt/annotations/doc/reference/en/modules/setup.xml 2007-02-28 02:06:13 UTC (rev 11248)
+++ branches/Branch_3_2/HibernateExt/annotations/doc/reference/en/modules/setup.xml 2007-03-01 08:29:34 UTC (rev 11249)
@@ -48,7 +48,6 @@
<filename>lib/ejb3-persistence.jar</filename> from the Hibernate
Annotations distribution to your classpath as well.</para>
</listitem>
-
</itemizedlist></para>
<para>If you wish to use Hibernate Validator (TODO make a link to HV doc),
@@ -156,4 +155,40 @@
hbm</literal> will prioritize the annotated classes over hbm files when a
conflict occurs.</para>
</section>
+
+ <section>
+ <title id="setup-properties">Properties</title>
+
+ <para>Asides from the Hibernate core properties, Hibernate Annotations
+ reacts to the following one</para>
+
+ <table>
+ <title>List of properties</title>
+
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry align="center">Property</entry>
+
+ <entry align="center">Definition</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>hibernate.validator.apply_to_ddl</entry>
+
+ <entry>Use Hibernate Validator annotations to refine the database
+ schema generation. Default to true.</entry>
+ </row>
+
+ <row>
+ <entry></entry>
+
+ <entry></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
</chapter>
\ No newline at end of file
Modified: branches/Branch_3_2/HibernateExt/annotations/src/java/org/hibernate/annotations/Table.java
===================================================================
--- branches/Branch_3_2/HibernateExt/annotations/src/java/org/hibernate/annotations/Table.java 2007-02-28 02:06:13 UTC (rev 11248)
+++ branches/Branch_3_2/HibernateExt/annotations/src/java/org/hibernate/annotations/Table.java 2007-03-01 08:29:34 UTC (rev 11249)
@@ -31,7 +31,7 @@
/**
* Defines the Foreign Key name of a secondary table
- * back to the primary table
+ * pointing back to the primary table
*/
ForeignKey foreignKey() default @ForeignKey( name="" );
@@ -49,7 +49,7 @@
FetchMode fetch() default FetchMode.JOIN;
/**
- * If enabled, Hibernate will not try to insert or update the properties defined by this join.
+ * If true, Hibernate will not try to insert or update the properties defined by this join.
*
* <b>Only applies to secondary tables</b>
*/
Modified: branches/Branch_3_2/HibernateExt/annotations/src/java/org/hibernate/annotations/Tuplizer.java
===================================================================
--- branches/Branch_3_2/HibernateExt/annotations/src/java/org/hibernate/annotations/Tuplizer.java 2007-02-28 02:06:13 UTC (rev 11248)
+++ branches/Branch_3_2/HibernateExt/annotations/src/java/org/hibernate/annotations/Tuplizer.java 2007-03-01 08:29:34 UTC (rev 11249)
@@ -16,6 +16,6 @@
public @interface Tuplizer {
/** tuplizer implementation */
Class impl();
- /** either pojo, dynamic-map or domj4 */
+ /** either pojo, dynamic-map or dom4j� */
String entityMode() default "pojo";
}
Modified: branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/architecture.xml
===================================================================
--- branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/architecture.xml 2007-02-28 02:06:13 UTC (rev 11248)
+++ branches/Branch_3_2/HibernateExt/search/doc/reference/en/modules/architecture.xml 2007-03-01 08:29:34 UTC (rev 11249)
@@ -1,46 +1,80 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
+<?xml version="1.0" encoding="UTF-8"?>
<chapter id="search-architecture">
- <title>Architecture</title>
+ <title>Architecture</title>
- <para>Hibernate Search is made of an indexing engine and an index search
- engine. Both are backed by Apache Lucene.
- </para>
+ <para>Hibernate Search is made of an indexing engine and an index search
+ engine. Both are backed by Apache Lucene.</para>
- <para>When an entity is inserted, updated or removed to/from the database,
- <productname>Hibernate Search</productname>
- will keep track of this event
- (through the Hibernate event system) and schedule an index update. When
- out of transaction, the update is executed right after the actual database
- operation. It is however recommended, for both your database and Hibernate
- Search, to execute your operation in a transaction (whether JDBC or JTA).
- When in a transaction, the index update is schedule for the transaction
- commit (and discarded in case of transaction rollback). You can think of
- this as the regular (infamous) autocommit vs transactional behavior. From
- a performance perspective, the
- <emphasis>in transaction</emphasis>
- mode is
- recommended. All the index updates are handled for you without you having
- to use the Apache Lucene APIs.
- </para>
+ <para>When an entity is inserted, updated or removed to/from the database,
+ <productname>Hibernate Search</productname> will keep track of this event
+ (through the Hibernate event system) and schedule an index update. When out
+ of transaction, the update is executed right after the actual database
+ operation. It is however recommended, for both your database and Hibernate
+ Search, to execute your operation in a transaction (whether JDBC or JTA).
+ When in a transaction, the index update is schedule for the transaction
+ commit (and discarded in case of transaction rollback). You can think of
+ this as the regular (infamous) autocommit vs transactional behavior. From a
+ performance perspective, the <emphasis>in transaction</emphasis> mode is
+ recommended. All the index updates are handled for you without you having to
+ use the Apache Lucene APIs.</para>
- <para>To interact with Apache Lucene indexes, Hibernate Search has the
- notion of
- <classname>DirectoryProvider</classname>
- . A directory provider
- will manage a given Lucene
- <classname>Directory</classname>
- type. You can
- configure directory providers to adjust the directory target.
- </para>
+ <para>To interact with Apache Lucene indexes, Hibernate Search has the
+ notion of <classname>DirectoryProvider</classname> . A directory provider
+ will manage a given Lucene <classname>Directory</classname> type. You can
+ configure directory providers to adjust the directory target.</para>
- <para>
- <productname>Hibernate Search</productname>
- can also use a Lucene
- index to search an entity and return a (list of) managed entity saving you
- from the tedious Object / Lucene Document mapping and low level Lucene
- APIs. The application code use the unified
- <classname>org.hibernate.Query</classname>
- API exactly the way a HQL or
- native query would be done.
- </para>
+ <para><productname>Hibernate Search</productname> can also use a Lucene
+ index to search an entity and return a (list of) managed entity saving you
+ from the tedious Object / Lucene Document mapping and low level Lucene APIs.
+ The application code use the unified
+ <classname>org.hibernate.Query</classname> API exactly the way a HQL or
+ native query would be done.</para>
+
+ <section>
+ <title>Backend</title>
+
+ <para>Hibernate Search offers the ability to process the</para>
+
+ <section>
+ <title>Lucene</title>
+
+ <para>In this mode, all index update operations applied on a given node
+ (JVM) will be executed to the Lucene directories (through the directory
+ providers) by the same node. This mode is typically used in non
+ clustered mode or in clustered mode where the directory store is shared.
+ </para>
+ </section>
+
+ <section>
+ <title>JMS</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Custom</title>
+
+ <para></para>
+ </section>
+ </section>
+
+ <section>
+ <title>Work execution</title>
+
+ <para>The indexing work can be executed synchronously with the transaction
+ commit (or update operation if out of transaction), or
+ asynchronously.</para>
+
+ <section>
+ <title>Synchronous</title>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Asynchronous</title>
+
+ <para></para>
+ </section>
+ </section>
</chapter>
\ No newline at end of file
Modified: branches/Branch_3_2/HibernateExt/validator/doc/reference/en/modules/checkconstraints.xml
===================================================================
--- branches/Branch_3_2/HibernateExt/validator/doc/reference/en/modules/checkconstraints.xml 2007-02-28 02:06:13 UTC (rev 11248)
+++ branches/Branch_3_2/HibernateExt/validator/doc/reference/en/modules/checkconstraints.xml 2007-03-01 08:29:34 UTC (rev 11249)
@@ -10,7 +10,7 @@
<para>This chapter will cover Hibernate Validator usage for different
layers</para>
- <section id="validator-checkconstraints-db" revision="1">
+ <section id="validator-checkconstraints-db" revision="2">
<title>Database schema-level validation</title>
<para>Out of the box, Hibernate Annotations will translate the constraints
@@ -21,6 +21,10 @@
<para>Using hbm2ddl, domain model constraints will be expressed into the
database schema.</para>
+
+ <para>If, for some reason, the feature needs to be disabled, set
+ <literal>hibernate.validator.apply_to_ddl</literal> to
+ <literal>false</literal>.</para>
</section>
<section id="validator-checkconstraints-orm">
@@ -83,7 +87,6 @@
@EntityListeners( JPAValidateListener.class )
public class Submarine {
...
-}
}</programlisting>
<para><note>
@@ -108,10 +111,10 @@
<para>The first two lines prepare the Hibernate Validator for class
checking. The first one relies upon the error messages embedded in
- Hibernate Validator (see <xref linkend="validator-defineconstraints-error" />),
- the second one uses a resource bundle for these messages. It is considered
- a good practice to execute these lines once and cache the validator
- instances.</para>
+ Hibernate Validator (see <xref
+ linkend="validator-defineconstraints-error" />), the second one uses a
+ resource bundle for these messages. It is considered a good practice to
+ execute these lines once and cache the validator instances.</para>
<para>The third line actually validates the <literal>Address</literal>
instance and returns an array of <literal>InvalidValue</literal>s. Your
@@ -162,8 +165,8 @@
additional JSF tags, again without validation definition
duplication.</para>
- <para>Check the <ulink url="http://www.jboss.com/products/seam">JBoss Seam</ulink>
- documentation for more information.</para>
+ <para>Check the <ulink url="http://www.jboss.com/products/seam">JBoss
+ Seam</ulink> documentation for more information.</para>
</section>
<section>
Modified: branches/Branch_3_2/HibernateExt/validator/doc/reference/en/modules/defineconstraints.xml
===================================================================
--- branches/Branch_3_2/HibernateExt/validator/doc/reference/en/modules/defineconstraints.xml 2007-02-28 02:06:13 UTC (rev 11248)
+++ branches/Branch_3_2/HibernateExt/validator/doc/reference/en/modules/defineconstraints.xml 2007-03-01 08:29:34 UTC (rev 11249)
@@ -12,7 +12,7 @@
element.</para>
</section>
- <section id="validator-defineconstraints-builtin" revision="1">
+ <section id="validator-defineconstraints-builtin" revision="2">
<title>Built in constraints</title>
<para>Hibernate Validator comes with some built-in constraints, which
@@ -112,7 +112,8 @@
</row>
<row>
- <entry>@Pattern(regex="regexp", flag=)</entry>
+ <entry>@Pattern(regex="regexp", flag=) or @Patterns(
+ {@Pattern(...)} )</entry>
<entry>property (string)</entry>
@@ -191,6 +192,54 @@
<entry>none</entry>
</row>
+
+ <row>
+ <entry>@CreditCardNumber</entry>
+
+ <entry>property (String)</entry>
+
+ <entry>check whether the string is a well formated credit card
+ number (derivative of the Luhn algorithm)</entry>
+
+ <entry>none</entry>
+ </row>
+
+ <row>
+ <entry>@Digits</entry>
+
+ <entry>property (numeric or string representation of a
+ numeric)</entry>
+
+ <entry>check whether the property is a number having up to
+ <literal>integerDigits</literal> integer digits and
+ <literal>fractionalDigits</literal> fractonal digits</entry>
+
+ <entry>define column precision and scale</entry>
+ </row>
+
+ <row>
+ <entry>@EAN</entry>
+
+ <entry>property (string)</entry>
+
+ <entry>check whether the string is a properly formated EAN or
+ UPC-A code</entry>
+
+ <entry>none</entry>
+ </row>
+
+ <row>
+ <entry>@Digits</entry>
+
+ <entry>property (numeric or string representation of a
+ numeric)</entry>
+
+ <entry>check whether the property is a number having up to
+ <literal>integerDigits</literal> integer digits and
+ <literal>fractionalDigits</literal> fractonal digits</entry>
+
+ <entry>define column precision and scale</entry>
+ </row>
</tbody>
</tgroup>
</table>
@@ -217,7 +266,7 @@
JavaDoc for more informations).</para>
</section>
- <section>
+ <section id="validator-defineconstraints-own" revision="1">
<title>Writing your own constraints</title>
<para>Extending the set of built-in constraints is extremely easy. Any
@@ -247,7 +296,8 @@
<literal>Capitalization is not {type}</literal> would generate
<literal>Capitalization is not FIRST</literal> ), externalizing the whole
string in <filename>ValidatorMessages.properties</filename> is considered
- good practice. See <xref linkend="validator-defineconstraints-error" /> .</para>
+ good practice. See <xref linkend="validator-defineconstraints-error" />
+ .</para>
<programlisting>@ValidatorClass(CapitalizedValidator.class)
@Target(METHOD)
@@ -311,6 +361,28 @@
of a property, the bean itself will be passed to the validator. To
activate the validation checking, just annotated the bean itself instead.
A small sample can be found in the unit test suite.</para>
+
+ <para>If your constraint can be applied multiple times (with different
+ parameters) on the same property or type, you can use the following
+ annotation form:</para>
+
+ <programlisting>@Target(METHOD)
+@Retention(RUNTIME)
+@Documented
+<emphasis role="bold">public @interface Patterns {</emphasis>
+ Pattern[] value();
+}
+
+@Target(METHOD)
+@Retention(RUNTIME)
+@Documented
+(a)ValidatorClass(PatternValidator.class)
+public @interface Pattern {
+ String regexp();
+}</programlisting>
+
+ <para>Basically an annotation containing the value attribute as an array
+ of validator annotations.</para>
</section>
<section>
18 years, 7 months