Java Mailing List Archive

http://www.gg3721.com/

Home » Hibernate Commits List »

[hibernate-commits] Hibernate SVN: r14690 - in search/trunk:
 src/java/org/hibernate/search/backend and 3 other directories.

hibernate-commits

2008-05-26


Author LoginPost Reply
Author: sannegrinovero
Date: 2008-05-26 19:04:52 -0400 (Mon, 26 May 2008)
New Revision: 14690

Added:
 search/trunk/src/java/org/hibernate/search/backend/configuration/MaskedProperty.java
 search/trunk/src/test/org/hibernate/search/test/configuration/MaskedPropertiesTest.java
Modified:
 search/trunk/doc/reference/en/modules/batchindex.xml
 search/trunk/doc/reference/en/modules/configuration.xml
 search/trunk/doc/reference/en/modules/optimize.xml
 search/trunk/src/java/org/hibernate/search/backend/LuceneIndexingParameters.java
 search/trunk/src/java/org/hibernate/search/backend/configuration/IndexWriterSetting.java
 search/trunk/src/java/org/hibernate/search/store/DirectoryProviderFactory.java
 search/trunk/src/test/org/hibernate/search/test/configuration/ConfigurationReadTestCase.java
 search/trunk/src/test/org/hibernate/search/test/configuration/LuceneIndexingParametersTest.java
 search/trunk/src/test/org/hibernate/search/test/configuration/ShardsConfigurationTest.java
Log:
HSEARCH-200: more IndexWriter settings available, some changes about configuration parsing;
Also includes related Documentation changes, and some unrelated documentation typos.

Modified: search/trunk/doc/reference/en/modules/batchindex.xml
===================================================================
--- search/trunk/doc/reference/en/modules/batchindex.xml  2008-05-23 21:42:40 UTC (rev 14689)
+++ search/trunk/doc/reference/en/modules/batchindex.xml  2008-05-26 23:04:52 UTC (rev 14690)
@@(protected) @@

  <para>Other parameters which also can affect indexing time and memory
  consumption are
-   <literal>hibernate.search.[default|&lt;indexname&gt;].batch.merge_factor</literal>
+   <literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.batch.max_buffered_docs</literal>
  ,
-   <literal>hibernate.search.[default|&lt;indexname&gt;].batch.max_merge_docs</literal>
+   <literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.batch.max_field_length</literal>
  ,
-   <literal>hibernate.search.[default|&lt;indexname&gt;].batch.max_buffered_docs</literal>
+   <literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.batch.max_merge_docs</literal>
+   ,
+   <literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.batch.merge_factor</literal>
+   ,
+   <literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.batch.ram_buffer_size</literal>
  and
-   <literal>hibernate.search.[default|&lt;indexname&gt;].batch.ram_buffer_size</literal>
+   <literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.batch.term_index_interval</literal>
  . These parameters are Lucene specific and Hibernate Search is just
  passing these paramters through - see <xref
  linkend="lucene-indexing-performance" /> for more details.</para>
@@(protected) @@
  <note>
    <para>Methods <methodname>index</methodname>,
    <methodname>purge</methodname> and <methodname>purgeAll</methodname> are
-    available on <classname>FullTextEntityManager</classname> as well</para>
+    available on <classname>FullTextEntityManager</classname> as well.</para>
  </note>
 </section>
</chapter>

Modified: search/trunk/doc/reference/en/modules/configuration.xml
===================================================================
--- search/trunk/doc/reference/en/modules/configuration.xml  2008-05-23 21:42:40 UTC (rev 14689)
+++ search/trunk/doc/reference/en/modules/configuration.xml  2008-05-26 23:04:52 UTC (rev 14690)
@@(protected) @@

    <programlisting>@(protected) = {
    @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
-    @ActivationConfigProperty(propertyName="destination", propertyValue="queue/hiebrnatesearch"),
+    @ActivationConfigProperty(propertyName="destination", propertyValue="queue/hibernatesearch"),
    @ActivationConfigProperty(propertyName="DLQMaxResent", propertyValue="1")
  } )
public class MDBSearchController extends AbstractJMSHibernateSearchController implements MessageListener {
@@(protected) @@
  </section>
 </section>

- <section id="lucene-indexing-performance" revision="2">
+ <section id="lucene-indexing-performance" revision="3">
  <title>Tuning Lucene indexing performance</title>

  <para>Hibernate Search allows you to tune the Lucene indexing performance
@@(protected) @@
  Lucene <literal>IndexWriter</literal> such as
  <literal>mergeFactor</literal>, <literal>maxMergeDocs</literal> and
  <literal>maxBufferedDocs</literal>. You can specify these parameters
-   either as default values applying for all indexes or on a per index
-   basis.</para>
+   either as default values applying for all indexes, on a per index
+   basis, or even per shard.</para>

  <para>There are two sets of parameters allowing for different performance
  settings depending on the use case. During indexing operations triggered
-   by database modifications, the following ones are used: <itemizedlist>
-     <listitem>
-       <para><literal>hibernate.search.[default|&lt;indexname&gt;].transaction.merge_factor</literal></para>
-     </listitem>
+   by database modifications, the parameters are grouped by the
+   <literal>transaction</literal> keyword:
+   <programlisting>hibernate.search.[default|&lt;indexname&gt;].indexwriter.transaction.&lt;parameter_name&gt;</programlisting>
+   When indexing occurs via <literal>FullTextSession.index()</literal> (see <xref
+   linkend="search-batchindex" />), the used properties are those grouped under the <literal>batch</literal> keyword:
+   <programlisting>hibernate.search.[default|&lt;indexname&gt;].indexwriter.batch.&lt;parameter_name&gt;</programlisting>
+   </para>

-     <listitem>
-       <para><literal>hibernate.search.[default|&lt;indexname&gt;].transaction.max_merge_docs</literal></para>
-     </listitem>
-
-     <listitem>
-       <para><literal>hibernate.search.[default|&lt;indexname&gt;].transaction.max_buffered_docs</literal></para>
-     </listitem>
-    
-     <listitem>
-       <para><literal>hibernate.search.[default|&lt;indexname&gt;].transaction.ram_buffer_size</literal></para>
-     </listitem>
-    </itemizedlist>When indexing occurs via
-   <literal>FullTextSession.index()</literal> (see <xref
-   linkend="search-batchindex" />), the following properties are used:
-   <itemizedlist>
-     <listitem>
-       <para><literal>hibernate.search.[default|&lt;indexname&gt;].batch.merge_factor</literal></para>
-     </listitem>
-
-     <listitem>
-       <para><literal>hibernate.search.[default|&lt;indexname&gt;].batch.max_merge_docs</literal></para>
-     </listitem>
-
-     <listitem>
-       <para><literal>hibernate.search.[default|&lt;indexname&gt;].batch.max_buffered_docs</literal></para>
-     </listitem>
-    
-     <listitem>
-       <para><literal>hibernate.search.[default|&lt;indexname&gt;].batch.ram_buffer_size</literal></para>
-     </listitem>
-    </itemizedlist></para>
-
  <para>Unless the corresponding <literal>.batch</literal> property is
  explicitly set, the value will default to the
-   <literal>.transaction</literal> property.</para>
+   <literal>.transaction</literal> property.
+   If no value is set for a <literal>.batch</literal> value in a specific shard configuration,
+   Hibernate Search will look at the index section, then at the default section and after that
+   it will look for a <literal>.transaction</literal> in the same order:
+   <programlisting>
+   hibernate.search.Animals.2.indexwriter.transaction.max_merge_docs 10
+   hibernate.search.Animals.2.indexwriter.transaction.merge_factor 20
+   hibernate.search.default.indexwriter.batch.max_merge_docs 100</programlisting>
+   This configuration will result in these settings applied to the second shard of Animals index:
+   <itemizedlist>
+    <listitem><literal>transaction.max_merge_docs</literal> = 10</listitem>
+     <listitem><literal>batch.max_merge_docs</literal> = 100</listitem>
+     <listitem><literal>transaction.merge_factor</literal> = 20</listitem>
+     <listitem><literal>batch.merge_factor</literal> = 20</listitem>
+   </itemizedlist>
+   All other values will use the defaults defined in Lucene.
+   </para>

  <para>
-   The default for all values is to leave them at Lucene's own default,
+   The default for all values is to leave them at Lucene&#39;s own default,
  so the listed values in the following table actually depend on the
  version of Lucene you are using;
  values shown are relative to version <literal>2.3</literal>.
@@(protected) @@
     </thead>

     <tbody>
+    
      <row>
-        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].transaction.merge_factor</literal></entry>
+        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.[transaction|batch].max_buffered_delete_terms</literal></entry>

-        <entry><para>Controls segment merge frequency and size. </para>
-        <para>Determines how often segment indices are merged when
-        insertion occurs. With smaller values, less RAM is used while
-        indexing, and searches on unoptimized indices are faster, but
-        indexing speed is slower. With larger values, more RAM is used
-        during indexing, and while searches on unoptimized indices are
-        slower, indexing is faster. Thus larger values (&gt; 10) are best
-        for batch index creation, and smaller values (&lt; 10) for indices
-        that are interactively maintained. The value must no be lower than
-        2.</para> <para>Used by Hibernate Search during index update
-        operations as part of database modifications.</para></entry>
+        <entry><para>Determines the minimal number of delete terms required before the buffered
+      in-memory delete terms are applied and flushed. If there are documents
+      buffered in memory at the time, they are merged and a new segment is
+        created.</para></entry>

-        <entry>10</entry>
+        <entry>Disabled (flushes by RAM usage)</entry>
      </row>

      <row>
-        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].transaction.max_merge_docs</literal></entry>
+        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.[transaction|batch].max_buffered_docs</literal></entry>

-        <entry><para>Defines the largest number of documents allowed in a
-        segment.</para> <para>Used by Hibernate Search during index update
-        operations as part of database modifications.</para></entry>
+        <entry><para>Controls the amount of documents buffered in memory
+        during indexing. The bigger the more RAM is consumed.</para>
+       </entry>

-        <entry>Unlimited (Integer.MAX_VALUE)</entry>
+        <entry>Disabled (flushes by RAM usage)</entry>
      </row>

      <row>
-        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].transaction.max_buffered_docs</literal></entry>
+        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.[transaction|batch].max_field_length</literal></entry>

-        <entry><para>Controls the amount of documents buffered in memory
-        during indexing. The bigger the more RAM is consumed.</para>
-        <para>Used by Hibernate Search during index update operations as
-        part of database modifications.</para></entry>
+        <entry><para>The maximum number of terms that will be indexed for a single field.
+        This limits the amount of memory required for indexing so that very large data will not crash the indexing process by
+      running out of memory. This setting refers to the number of running terms,
+      not to the number of different terms.</para>
+      <para>This silently truncates large documents, excluding from the index all terms that occur further in the document.
+      If you know your source documents are large, be sure to set this value high enough to accomodate the expected size.
+      If you set it to Integer.MAX_VALUE, then the only limit is your memory, but you should anticipate an OutOfMemoryError.
+      </para>
+      <para>If setting this value in <literal>batch</literal> differently than in <literal>transaction</literal>
+      you may get different data (and results) in your index depending on the indexing mode.</para>
+       </entry>

-        <entry>Disabled (not set)</entry>
+        <entry>10000</entry>
      </row>
     
      <row>
-        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].transaction.ram_buffer_size</literal></entry>
+        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.[transaction|batch].max_merge_docs</literal></entry>

-        <entry><para>Controls the amount of RAM in MB dedicated to document buffers.
-        When used together max_buffered_docs a flush occurs for whichever event happens first.</para>
-        <para>Generally for faster indexing performance it's best to flush by RAM usage instead of document
-        count and use as large a RAM buffer as you can.</para>
-        <para>Used by Hibernate Search during index update operations as
-        part of database modifications.</para></entry>
+        <entry><para>Defines the largest number of documents allowed in a segment.
+        Larger values are best for batched indexing and speedier searches.
+        Small values are best for transaction indexing.</para></entry>

-        <entry>16 MB</entry>
+        <entry>Unlimited (Integer.MAX_VALUE)</entry>
      </row>

      <row>
-        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].batch.merge_factor</literal></entry>
+        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.[transaction|batch].merge_factor</literal></entry>

-        <entry><para>Controls segment merge frequency and size.</para>
+        <entry><para>Controls segment merge frequency and size. </para>
        <para>Determines how often segment indices are merged when
        insertion occurs. With smaller values, less RAM is used while
        indexing, and searches on unoptimized indices are faster, but
@@(protected) @@
        slower, indexing is faster. Thus larger values (&gt; 10) are best
        for batch index creation, and smaller values (&lt; 10) for indices
        that are interactively maintained. The value must no be lower than
-        2.</para> <para>Used during indexing via
-        <literal>FullTextSession.index()</literal></para></entry>
+        2.</para></entry>

        <entry>10</entry>
      </row>

      <row>
-        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].batch.max_merge_docs</literal></entry>
+        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.[transaction|batch].ram_buffer_size</literal></entry>

-        <entry><para>Defines the largest number of documents allowed in a
-        segment.</para> <para>Used during indexing via
-        <literal>FullTextSession.index()</literal></para></entry>
-
-        <entry>Unlimited (Integer.MAX_VALUE)</entry>
-       </row>
-
-       <row>
-        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].batch.max_buffered_docs</literal></entry>
-
-        <entry><para>Controls the amount of documents buffered in memory
-        during indexing. The bigger the more RAM is consumed.</para>
-        <para>Used during indexing via
-        <literal>FullTextSession.index()</literal></para></entry>
-
-        <entry>Disabled (not set)</entry>
-       </row>
-      
-       <row>
-        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].batch.ram_buffer_size</literal></entry>
-
        <entry><para>Controls the amount of RAM in MB dedicated to document buffers.
        When used together max_buffered_docs a flush occurs for whichever event happens first.</para>
        <para>Generally for faster indexing performance it's best to flush by RAM usage instead of document
       count and use as large a RAM buffer as you can.</para>
-        <para>Used during indexing via
-        <literal>FullTextSession.index()</literal></para></entry>
+        </entry>

        <entry>16 MB</entry>
      </row>
+       <row>
+        <entry><literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.[transaction|batch].term_index_interval</literal></entry>
+
+        <entry><para>Expert: Set the interval between indexed terms.</para>
+        <para>Large values cause less memory to be used by IndexReader, but slow random-access to terms.
+        Small values cause more memory to be used by an IndexReader, and speed
+        random-access to terms. See Lucene documentation for more details.</para>
+        </entry>
+
+        <entry>128</entry>
+       </row>
+
     </tbody>
    </tgroup>
  </table>

Modified: search/trunk/doc/reference/en/modules/optimize.xml
===================================================================
--- search/trunk/doc/reference/en/modules/optimize.xml  2008-05-23 21:42:40 UTC (rev 14689)
+++ search/trunk/doc/reference/en/modules/optimize.xml  2008-05-26 23:04:52 UTC (rev 14690)
@@(protected) @@
 <title>Index Optimization</title>

 <para>From time to time, the Lucene index needs to be optimized. The process
- is essentially a defragmentation: until the optimization occurs, deleted
- documents are just marked as such, no physical deletion is applied, the
+ is essentially a defragmentation: until the optimization occurs deleted
+ documents are just marked as such, no physical deletion is applied; the
 optimization can also adjust the number of files in the Lucene
 Directory.</para>

@@(protected) @@

  <programlisting>hibernate.search.default.optimizer.operation_limit.max = 1000
hibernate.search.default.optimizer.transaction_limit.max = 100
-
hibernate.search.Animal.optimizer.transaction_limit.max = 50</programlisting>

  <para>An optimization will be triggered to the <literal>Animal</literal>
@@(protected) @@
    </listitem>
  </itemizedlist>

-   <para>If none of these parameters are defined, not optimization is
+   <para>If none of these parameters are defined, no optimization is
  processed automatically.</para>
 </section>

@@(protected) @@
  <title>Manual optimization</title>

  <para>You can programmatically optimize (defragment) a Lucene index from
-   Hibernate Search through the <classname>SearchFactory</classname></para>
+   Hibernate Search through the <classname>SearchFactory</classname>:</para>

-   <programlisting>searchFactory.optimize(Order.class);
+   <programlisting>searchFactory.optimize(Order.class);</programlisting>

-searchFactory.optimize();</programlisting>
+  <programlisting>searchFactory.optimize();</programlisting>

-   <para>The first example reindex the Lucene index holding
-   <classname>Order</classname>s, the second, optimize all indexes.</para>
+   <para>The first example optimizes the Lucene index holding
+   <classname>Order</classname>s; the second, optimizes all indexes.</para>

  <para>The <classname>SearchFactory</classname> can be accessed from a
  <classname>FullTextSession</classname>:</para>
@@(protected) @@
  <title>Adjusting optimization</title>

  <para>Apache Lucene has a few parameters to influence how optimization is
-   performed. Hibernate Search expose those parameters.</para>
+   performed. Hibernate Search exposes those parameters.</para>

-   <para>Further index optimisation parameters include
-   <literal>hibernate.search.[default|&lt;indexname&gt;].[batch|transaction].merge_factor</literal>,
-   <literal>hibernate.search.[default|&lt;indexname&gt;].[batch|transaction].max_merge_docs</literal>,
-   <literal>hibernate.search.[default|&lt;indexname&gt;].[batch|transaction].max_buffered_docs</literal>
-   and
-   <literal>hibernate.search.[default|&lt;indexname&gt;].[batch|transaction].ram_buffer_size</literal>
-   - see <xref linkend="lucene-indexing-performance" /> for more
-   details.</para>
+   <para>Further index optimisation parameters include:
+   <itemizedlist>
+    <listitem><literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.[batch|transaction].max_buffered_docs</literal></listitem>
+    <listitem><literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.[batch|transaction].max_field_length</literal></listitem>
+    <listitem><literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.[batch|transaction].max_merge_docs</literal></listitem>
+    <listitem><literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.[batch|transaction].merge_factor</literal></listitem>
+    <listitem><literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.[batch|transaction].ram_buffer_size</literal></listitem>
+    <listitem><literal>hibernate.search.[default|&lt;indexname&gt;].indexwriter.[batch|transaction].term_index_interval</literal></listitem>
+  </itemizedlist>
+   See <xref linkend="lucene-indexing-performance" /> for more details.</para>
 </section>
</chapter>

Modified: search/trunk/src/java/org/hibernate/search/backend/LuceneIndexingParameters.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/LuceneIndexingParameters.java  2008-05-23 21:42:40 UTC (rev 14689)
+++ search/trunk/src/java/org/hibernate/search/backend/LuceneIndexingParameters.java  2008-05-26 23:04:52 UTC (rev 14690)
@@(protected) @@
-//$Id$
-package org.hibernate.search.backend;
-
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-
-import org.apache.lucene.index.IndexWriter;
-import org.hibernate.search.SearchException;
-import org.hibernate.search.backend.configuration.IndexWriterSetting;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Wrapper class around the Lucene indexing parameters <i>mergeFactor</i>, <i>maxMergeDocs</i>,
- * <i>maxBufferedDocs</i>, <i>termIndexInterval</i>, <i>RAMBufferSizeMB</i>.
- * <p>
- * There are two sets of these parameters. One is for regular indexing the other is for batch indexing
- * triggered by <code>FullTextSessoin.index(Object entity)</code>
- *
- * @author Hardy Ferentschik
- * @author Sanne Grinovero
- */
-public class LuceneIndexingParameters implements Serializable {
-
-  // value keyword
-  public static final String EXPLICIT_DEFAULT_VALUE = "default";
-  // property path keywords
-  public static final String BATCH = "batch";
-  public static final String TRANSACTION = "transaction";
-  
-  private final ParameterSet transactionIndexParameters;
-  private final ParameterSet batchIndexParameters;
-  
-  public LuceneIndexingParameters( Properties sourceProps ) {
-    Properties transactionProps = new Properties();
-    Properties batchProps = new Properties( transactionProps ); // transaction settings is the default for batch
-    //don't iterate on property entries we know all the keys:
-    for ( IndexWriterSetting t : IndexWriterSetting.values() ) {
-      String key = t.getKey();
-      String trxValue = sourceProps.getProperty( TRANSACTION + "." + key );
-      if (trxValue != null) {
-        transactionProps.setProperty( key, trxValue );
-      }
-      String batchValue = sourceProps.getProperty( BATCH + "." + key );
-      if (batchValue != null) {
-        batchProps.setProperty( key, batchValue );
-      }
-    }
-    transactionIndexParameters = new ParameterSet(transactionProps);
-    batchIndexParameters = new ParameterSet(batchProps);
-  }
-
-  public ParameterSet getTransactionIndexParameters() {
-    return transactionIndexParameters;
-  }
-
-  public ParameterSet getBatchIndexParameters() {
-    return batchIndexParameters;
-  }
-
-  public class ParameterSet implements Serializable {
-    
-    final Map<IndexWriterSetting, Integer> parameters = new HashMap<IndexWriterSetting, Integer>();
-    
-    public ParameterSet(Properties prop) {
-      for ( IndexWriterSetting t : IndexWriterSetting.values() ) {
-        String value = prop.getProperty( t.getKey() );
-        if ( ! (value==null || EXPLICIT_DEFAULT_VALUE.equals(value) ) ) {
-          parameters.put( t, t.parseVal(value) );
-        }
-      }
-    }
-    
-    /**
-     * Applies the parameters represented by this to a writer.
-     * Undefined parameters are not set, leaving the lucene default.
-     * @param writer the IndexWriter whereto the parameters will be applied.
-     */
-    public void applyToWriter(IndexWriter writer) {
-      for ( Map.Entry<IndexWriterSetting,Integer> entry : parameters.entrySet() ) {
-        try {
-          entry.getKey().applySetting( writer, entry.getValue() );
-        } catch ( IllegalArgumentException e ) {
-          //TODO if DirectoryProvider had getDirectoryName() exceptions could tell better
-          throw new SearchException( "Illegal IndexWriter setting "
-              + entry.getKey().getKey() + " "+ e.getMessage(), e );
-        }
-      }
-    }
-    
-    public Integer getCurrentValueFor(IndexWriterSetting ws){
-      return parameters.get(ws);
-    }
-    
-    public void setCurrentValueFor(IndexWriterSetting ws, Integer newValue){
-      if (newValue==null){
-        parameters.remove(ws);
-      } else {
-        parameters.put(ws, newValue);
-      }
-    }
-
-  }
-  
-}
+//$Id$
+package org.hibernate.search.backend;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.lucene.index.IndexWriter;
+import org.hibernate.search.SearchException;
+import org.hibernate.search.backend.configuration.IndexWriterSetting;
+import org.hibernate.search.backend.configuration.MaskedProperty;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.hibernate.search.backend.configuration.IndexWriterSetting.MAX_FIELD_LENGTH;
+
+/**
+ * Wrapper class around the Lucene indexing parameters defined in IndexWriterSetting.
+ * <p>
+ * There are two sets of these parameters. One is for regular indexing the other is for batch indexing
+ * triggered by <code>FullTextSessoin.index(Object entity)</code>
+ *
+ * @author Hardy Ferentschik
+ * @author Sanne Grinovero
+ */
+public class LuceneIndexingParameters implements Serializable {
+
+  private static final long serialVersionUID = 5424606407623591663L;
+  private static Logger log = LoggerFactory.getLogger( LuceneIndexingParameters.class );
+  
+  // value keyword
+  public static final String EXPLICIT_DEFAULT_VALUE = "default";
+  // property path keywords
+  public static final String BATCH = "batch";
+  public static final String TRANSACTION = "transaction";
+  public static final String PROP_GROUP = "indexwriter";
+  
+  private final ParameterSet transactionIndexParameters;
+  private final ParameterSet batchIndexParameters;
+  
+  public LuceneIndexingParameters( Properties sourceProps ) {
+    //prefer keys under "indexwriter" but fallback for backwards compatibility:
+    Properties indexingParameters = new MaskedProperty( sourceProps, PROP_GROUP, sourceProps );
+    //get keys for "transaction"
+    Properties transactionProps = new MaskedProperty( indexingParameters, TRANSACTION );
+    //get keys for "batch" (defaulting to transaction)
+    Properties batchProps = new MaskedProperty( indexingParameters, BATCH, transactionProps ); //TODO to close HSEARCH-201 just remove 3° parameter
+    transactionIndexParameters = new ParameterSet( transactionProps, TRANSACTION );
+    batchIndexParameters = new ParameterSet( batchProps, BATCH );
+    doSanityChecks( transactionIndexParameters, batchIndexParameters );
+  }
+
+  private void doSanityChecks(ParameterSet transParams, ParameterSet batchParams) {
+    if ( log.isWarnEnabled() ) {
+      Integer maxFieldLengthTransaction = transParams.parameters.get( MAX_FIELD_LENGTH );
+      Integer maxFieldLengthBatch = transParams.parameters.get( MAX_FIELD_LENGTH );
+      if ( notEquals( maxFieldLengthTransaction, maxFieldLengthBatch ) ){
+        log.warn( "The max_field_length value configured for transaction is different than the value configured for batch." );
+      }
+    }
+  }
+
+  private boolean notEquals(Integer a, Integer b) {
+    if ( a==null && b==null ) return false;
+    if ( a==null && b!=null ) return true;
+    if ( a!=null && b==null ) return true;
+    return a.intValue() != b.intValue();
+  }
+
+  public ParameterSet getTransactionIndexParameters() {
+    return transactionIndexParameters;
+  }
+
+  public ParameterSet getBatchIndexParameters() {
+    return batchIndexParameters;
+  }
+
+  public class ParameterSet implements Serializable {
+    
+    private static final long serialVersionUID = -6121723702279869524L;
+    
+    final Map<IndexWriterSetting, Integer> parameters = new HashMap<IndexWriterSetting, Integer>();
+    
+    public ParameterSet(Properties prop, String paramName) {
+      //don't iterate on property entries as we know all the keys:
+      for ( IndexWriterSetting t : IndexWriterSetting.values() ) {
+        String key = t.getKey();
+        String value = prop.getProperty( key );
+        if ( ! ( value==null || EXPLICIT_DEFAULT_VALUE.equalsIgnoreCase( value ) ) ) {
+          if ( log.isDebugEnabled() ) {
+            //TODO add DirectoryProvider name when available to log message
+            log.debug( "Set indexwriter parameter " + paramName +"." + key + " to value : "+ value );
+          }
+          parameters.put( t, t.parseVal( value ) );
+        }
+      }
+    }
+    
+    /**
+     * Applies the parameters represented by this to a writer.
+     * Undefined parameters are not set, leaving the lucene default.
+     * @param writer the IndexWriter whereto the parameters will be applied.
+     */
+    public void applyToWriter(IndexWriter writer) {
+      for ( Map.Entry<IndexWriterSetting,Integer> entry : parameters.entrySet() ) {
+        try {
+          entry.getKey().applySetting( writer, entry.getValue() );
+        } catch ( IllegalArgumentException e ) {
+          //TODO if DirectoryProvider had getDirectoryName() exceptions could tell better
+          throw new SearchException( "Illegal IndexWriter setting "
+              + entry.getKey().getKey() + " "+ e.getMessage(), e );
+        }
+      }
+    }
+    
+    public Integer getCurrentValueFor(IndexWriterSetting ws){
+      return parameters.get(ws);
+    }
+
+    public void setCurrentValueFor(IndexWriterSetting ws, Integer newValue){
+      if (newValue==null){
+        parameters.remove(ws);
+      } else {
+        parameters.put(ws, newValue);
+      }
+    }
+
+  }
+
+}

Modified: search/trunk/src/java/org/hibernate/search/backend/configuration/IndexWriterSetting.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/configuration/IndexWriterSetting.java  2008-05-23 21:42:40 UTC (rev 14689)
+++ search/trunk/src/java/org/hibernate/search/backend/configuration/IndexWriterSetting.java  2008-05-26 23:04:52 UTC (rev 14690)
@@(protected) @@
import org.apache.lucene.index.IndexWriter;
import org.hibernate.search.SearchException;

+/**
+ * Represents possible options to be applied to an
+ * <code>org.apache.lucene.index.IndexWriter</code>
+ *
+ * @author Sanne Grinovero
+ */
public enum IndexWriterSetting implements Serializable {
-  
-  MERGE_FACTOR( "merge_factor" ) {
+  /**
+   * @see org.apache.lucene.index.IndexWriter.setMaxBufferedDeleteTerms(int)
+   */
+  MAX_BUFFERED_DELETE_TERMS( "max_buffered_delete_terms" ) {
   public void applySetting(IndexWriter writer, int value) {
-      writer.setMergeFactor( value );
+      writer.setMaxBufferedDeleteTerms( value );
   }
 } ,
+  /**
+   * @see org.apache.lucene.index.IndexWriter.setMaxBufferedDocs(int)
+   */
+  MAX_BUFFERED_DOCS( "max_buffered_docs" ) {
+    public void applySetting(IndexWriter writer, int value) {
+      writer.setMaxBufferedDocs( value );
+    }
+  } ,
+  /**
+   * @see org.apache.lucene.index.IndexWriter.setMaxFieldLength(int)
+   */
+  MAX_FIELD_LENGTH( "max_field_length" ) {
+    public void applySetting(IndexWriter writer, int value) {
+      writer.setMaxFieldLength( value );
+    }
+  } ,
+  /**
+   * @see org.apache.lucene.index.IndexWriter.setMaxMergeDocs(int)
+   */
 MAX_MERGE_DOCS( "max_merge_docs" ) {
   public void applySetting(IndexWriter writer, int value) {
     writer.setMaxMergeDocs( value );
   }
 } ,
-  MAX_BUFFERED_DOCS( "max_buffered_docs" ) {
+  /**
+   * @see org.apache.lucene.index.IndexWriter.setMergeFactor(int)
+   */
+  MERGE_FACTOR( "merge_factor" ) {
   public void applySetting(IndexWriter writer, int value) {
-      writer.setMaxBufferedDocs( value );
+      writer.setMergeFactor( value );
   }
 } ,
+  /**
+   * @see org.apache.lucene.index.IndexWriter.setRAMBufferSizeMB(int)
+   */
 RAM_BUFFER_SIZE( "ram_buffer_size" ) {
   public void applySetting(IndexWriter writer, int value) {
     writer.setRAMBufferSizeMB( value );
   }
+  },
+  /**
+   * @see org.apache.lucene.index.IndexWriter.setTermIndexInterval(int)
+   */
+  TERM_INDEX_INTERVAL( "term_index_interval" ) {
+    public void applySetting(IndexWriter writer, int value) {
+      writer.setTermIndexInterval( value );
+    }
 };
 
 private final String cfgKey;
 
-  IndexWriterSetting(String configurationKey){
+  IndexWriterSetting(String configurationKey) {
   this.cfgKey = configurationKey;
 }
 
@@(protected) @@
  */
 public abstract void applySetting(IndexWriter writer, int value);

+  /**
+   * @return The key used in configuration files to select an option.
+   */
 public String getKey() {
   return cfgKey;
 }

Added: search/trunk/src/java/org/hibernate/search/backend/configuration/MaskedProperty.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/configuration/MaskedProperty.java                  (rev 0)
+++ search/trunk/src/java/org/hibernate/search/backend/configuration/MaskedProperty.java  2008-05-26 23:04:52 UTC (rev 14690)
@@(protected) @@
+package org.hibernate.search.backend.configuration;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.InvalidPropertiesFormatException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper to Properties, to restrict the availability of
+ * values to only those which have a key beginning with some
+ * masking String.
+ * Methods to list available keys or values or otherwise
+ * enumerate available properties are not available.
+ *
+ * @author Sanne Grinovero
+ */
+public class MaskedProperty extends Properties implements Serializable {
+  
+  private static final long serialVersionUID = -593307257383085113L;
+  private static Logger log = LoggerFactory.getLogger( MaskedProperty.class );
+  
+  private final Properties masked;
+  private final Properties fallBack;
+  private final String radix;
+  
+  /**
+   * Provides a view to the provided Properties hiding
+   * all keys not starting with some [mask.].
+   * @param propsToMask the Properties containing the values.
+   * @param mask
+   */
+  public MaskedProperty(Properties propsToMask, String mask) {
+    this( propsToMask, mask, null );
+  }
+  
+  /**
+   * Provides a view to the provided Properties hiding
+   * all keys not starting with some [mask.].
+   * If no value is found then a value is returned from propsFallBack,
+   * without masking.
+   * @param propsToMask
+   * @param mask
+   * @param propsFallBack
+   */
+  public MaskedProperty(Properties propsToMask, String mask, Properties propsFallBack) {
+    if ( propsToMask==null || mask==null ) {
+      throw new java.lang.IllegalArgumentException();
+    }
+    this.masked = propsToMask;
+    this.radix = mask + ".";
+    this.fallBack = propsFallBack;
+  }
+  
+  @Override
+  public String getProperty(String key) {
+    String compositeKey = radix + key;
+    String value = masked.getProperty( compositeKey );
+    if ( value != null) {
+      log.trace( "found a match for key: [{}] value: {}", compositeKey, value );
+      return value;
+    }
+    else if ( fallBack != null ) {
+      return fallBack.getProperty( key );
+    }
+    else {
+      return null;
+    }
+  }
+
+  /**
+   * @throws IllegalArgumentException if the key is not a String instance
+   */
+  @Override
+  public boolean containsKey(Object key) {
+    if ( ! ( key instanceof String ) ) {
+      throw new IllegalArgumentException( "key must be a String" );
+    }
+    return getProperty( key.toString() ) != null;
+  }
+
+  @Override
+  public String getProperty(String key, String defaultValue) {
+    String val = getProperty( key );
+    return ( val == null ) ? defaultValue : val;
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public void list(PrintStream out) {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public void list(PrintWriter out) {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized void load(InputStream inStream) throws IOException {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized void loadFromXML(InputStream in) throws IOException,
+      InvalidPropertiesFormatException {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public Enumeration<?> propertyNames() {
+    throw new UnsupportedOperationException();
+  }
+  
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized void save(OutputStream out, String comments) {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized Object setProperty(String key, String value) {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized void store(OutputStream out, String comments)
+      throws IOException {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized void storeToXML(OutputStream os, String comment,
+      String encoding) throws IOException {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized void storeToXML(OutputStream os, String comment)
+      throws IOException {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized void clear() {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized Object clone() {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized boolean contains(Object value) {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public boolean containsValue(Object value) {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized Enumeration<Object> elements() {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public Set<java.util.Map.Entry<Object, Object>> entrySet() {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized Object get(Object key) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public synchronized boolean isEmpty() {
+    if ( fallBack==null ) {
+      return masked.isEmpty();
+    }
+    else {
+      return masked.isEmpty() && fallBack.isEmpty();
+    }
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized Enumeration<Object> keys() {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public Set<Object> keySet() {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized Object put(Object key, Object value) {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized void putAll(Map<? extends Object, ? extends Object> t) {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  protected void rehash() {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized Object remove(Object key) {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public synchronized int size() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public synchronized String toString() {
+    return masked.toString();
+  }
+
+  /**
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public Collection<Object> values() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = ( ( fallBack == null ) ? 0 : fallBack.hashCode() );
+    result = prime * result + masked.hashCode();
+    result = prime * result + radix.hashCode();
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if ( this == obj )
+      return true;
+    if ( getClass() != obj.getClass() )
+      return false;
+    final MaskedProperty other = (MaskedProperty) obj;
+    if ( fallBack == null ) {
+      if ( other.fallBack != null )
+        return false;
+    } else if ( ! fallBack.equals( other.fallBack ) )
+      return false;
+    if ( ! masked.equals( other.masked ) )
+      return false;
+    if ( ! radix.equals( other.radix ) )
+      return false;
+    return true;
+  }
+  
+}

Modified: search/trunk/src/java/org/hibernate/search/store/DirectoryProviderFactory.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/store/DirectoryProviderFactory.java  2008-05-23 21:42:40 UTC (rev 14689)
+++ search/trunk/src/java/org/hibernate/search/store/DirectoryProviderFactory.java  2008-05-26 23:04:52 UTC (rev 14690)
@@(protected) @@
-//$Id$
-package org.hibernate.search.store;
-
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.regex.Pattern;
-
-import org.hibernate.HibernateException;
-import org.hibernate.annotations.common.reflection.ReflectionManager;
-import org.hibernate.annotations.common.reflection.XClass;
-import org.hibernate.cfg.Configuration;
-import org.hibernate.mapping.PersistentClass;
-import org.hibernate.search.SearchException;
-import org.hibernate.search.annotations.Indexed;
-import org.hibernate.search.backend.LuceneIndexingParameters;
-import org.hibernate.search.engine.SearchFactoryImplementor;
-import org.hibernate.search.impl.SearchFactoryImpl;
-import org.hibernate.search.store.optimization.IncrementalOptimizerStrategy;
-import org.hibernate.search.store.optimization.NoOpOptimizerStrategy;
-import org.hibernate.search.store.optimization.OptimizerStrategy;
-import org.hibernate.util.ReflectHelper;
-import org.hibernate.util.StringHelper;
-
-/**
- * Create a Lucene directory provider
- * <p/>
- * Lucene directory providers are configured through properties
- * <ul>
- *  <li>hibernate.search.default.* and</li>
- *  <li>hibernate.search.&lt;indexname&gt;.*</li>
- * </ul>
- * <p/>
- * &lt;indexname&gt; properties have precedence over default
- * <p/>
- * The implementation is described by
- * hibernate.search.[default|indexname].directory_provider
- * <p/>
- * If none is defined the default value is FSDirectory
- *
- * @author Emmanuel Bernard
- * @author Sylvain Vieujot
- * @author Hardy Ferentschik
- */
-public class DirectoryProviderFactory {
-  private List<DirectoryProvider<?>> providers = new ArrayList<DirectoryProvider<?>>();
-  private static String LUCENE_PREFIX = "hibernate.search.";
-  private static String LUCENE_DEFAULT = LUCENE_PREFIX + "default.";
-  private static String DEFAULT_DIRECTORY_PROVIDER = FSDirectoryProvider.class.getName();
-  
-  private static final String SHARDING_STRATEGY = "sharding_strategy";
-  private static final String NBR_OF_SHARDS = SHARDING_STRATEGY + ".nbr_of_shards";
-  private static Pattern dotPattern = Pattern.compile( "\\." );
-
-
-  public DirectoryProviders createDirectoryProviders(XClass entity, Configuration cfg, SearchFactoryImplementor searchFactoryImplementor) {
-    //get properties
-    String directoryProviderName = getDirectoryProviderName( entity, cfg );
-    Properties[] indexProps = getDirectoryProperties( cfg, directoryProviderName );
-
-    //set up the directories
-    int nbrOfProviders = indexProps.length;
-    DirectoryProvider[] providers = new DirectoryProvider[nbrOfProviders];
-    for (int index = 0 ; index < nbrOfProviders ; index++) {
-      String providerName = nbrOfProviders > 1 ?
-          directoryProviderName + "." + index :
-          directoryProviderName;
-      providers[index] = createDirectoryProvider( providerName,indexProps[index], searchFactoryImplementor);
-    }
-
-    //define sharding strategy
-    IndexShardingStrategy shardingStrategy;
-    Properties shardingProperties = new Properties();
-    //we use an enumeration to get the keys from defaultProperties as well
-    Enumeration<String> allProps = (Enumeration<String>) indexProps[0].propertyNames();
-    while ( allProps.hasMoreElements() ){
-      String key = allProps.nextElement();
-      if ( key.startsWith( SHARDING_STRATEGY ) ) {
-        shardingProperties.put( key, indexProps[0].getProperty( key ) );
-      }
-    }
-
-    String shardingStrategyName = shardingProperties.getProperty( SHARDING_STRATEGY );
-    if ( shardingStrategyName == null) {
-      if ( indexProps.length == 1 ) {
-        shardingStrategy = new NotShardedStrategy();
-      }
-      else {
-        shardingStrategy = new IdHashShardingStrategy();
-      }
-    }
-    else {
-      try {
-        Class shardigStrategyClass = ReflectHelper.classForName( shardingStrategyName, this.getClass() );
-        shardingStrategy = (IndexShardingStrategy) shardigStrategyClass.newInstance();
-      }
-      catch (ClassNotFoundException e) {
-        throw new SearchException("Unable to find ShardingStrategy class " + shardingStrategyName + " for " + directoryProviderName, e);
-      }
-      catch (IllegalAccessException e) {
-        throw new SearchException("Unable to create instance of ShardingStrategy class " + shardingStrategyName
-            + " Be sure to have a no-arg constructor", e);
-      }
-      catch (InstantiationException e) {
-        throw new SearchException("Unable to create instance of ShardingStrategy class " + shardingStrategyName
-            + " Be sure to have a no-arg constructor", e);
-      }
-      catch (ClassCastException e) {
-        throw new SearchException("ShardingStrategy class does not implements DirecotryProviderShardingStrategy: "
-            + shardingStrategyName, e);
-      }
-    }
-    shardingStrategy.initialize( shardingProperties, providers );
-
-    return new DirectoryProviders( shardingStrategy, providers );
-  }
-
-  public void startDirectoryProviders() {
-    for ( DirectoryProvider provider : providers ) {
-      provider.start();
-    }
-  }
-
-  private DirectoryProvider<?> createDirectoryProvider(String directoryProviderName, Properties indexProps, SearchFactoryImplementor searchFactoryImplementor) {
-    String className = indexProps.getProperty( "directory_provider" );
-    if ( StringHelper.isEmpty( className ) ) {
-      className = DEFAULT_DIRECTORY_PROVIDER;
-    }
-    DirectoryProvider<?> provider;
-    try {
-      @SuppressWarnings( "unchecked" )
-      Class<DirectoryProvider> directoryClass = ReflectHelper.classForName(
-          className, DirectoryProviderFactory.class
-      );
-      provider = directoryClass.newInstance();
-    }
-    catch (Exception e) {
-      throw new HibernateException( "Unable to instanciate directory provider: " + className, e );
-    }
-    try {
-      provider.initialize( directoryProviderName, indexProps, searchFactoryImplementor );
-    }
-    catch (Exception e) {
-      throw new HibernateException( "Unable to initialize: " + directoryProviderName, e);
-    }
-    int index = providers.indexOf( provider );
-    if ( index != -1 ) {
-      //share the same Directory provider for the same underlying store
-      return providers.get( index );
-    }
-    else {
-      configureOptimizerStrategy(searchFactoryImplementor, indexProps, provider);
-      configureIndexingParameters(searchFactoryImplementor, indexProps, provider);
-      providers.add( provider );
-      if ( !searchFactoryImplementor.getLockableDirectoryProviders().containsKey( provider ) ) {
-        searchFactoryImplementor.getLockableDirectoryProviders().put( provider, new ReentrantLock() );
-      }
-      return provider;
-    }
-  }
-
-  private void configureOptimizerStrategy(SearchFactoryImplementor searchFactoryImplementor, Properties indexProps, DirectoryProvider<?> provider) {
-    boolean incremental = indexProps.containsKey( "optimizer.operation_limit.max" )
-        || indexProps.containsKey( "optimizer.transaction_limit.max" );
-    OptimizerStrategy optimizerStrategy;
-    if (incremental) {
-      optimizerStrategy = new IncrementalOptimizerStrategy();
-      optimizerStrategy.initialize( provider, indexProps, searchFactoryImplementor);
-    }
-    else {
-      optimizerStrategy = new NoOpOptimizerStrategy();
-    }
-    searchFactoryImplementor.addOptimizerStrategy(provider, optimizerStrategy);
-  }
-  
-  /**
-   * Creates a new <code>LuceneIndexingParameters</code> instance for the specified provider.
-   * If there are no matching properties in the configuration default values will be applied.
-   * <p>
-   * NOTE:</br>
-   * If a non batch value is set in the configuration apply it also to the
-   * batch mode. This covers the case where users only specify
-   * parameters for the non batch mode. In this case the same parameters apply for
-   * batch indexing.
-   * </p>
-   *
-   * @param searchFactoryImplementor the search factory.
-   * @param indexProps The properties extracted from the configuration.
-   * @param provider The directory provider for which to configure the indexing parameters.
-   */
-  private void configureIndexingParameters(SearchFactoryImplementor searchFactoryImplementor, Properties indexProps, DirectoryProvider<?> provider) {
-    LuceneIndexingParameters indexingParams = new LuceneIndexingParameters( indexProps );
-    searchFactoryImplementor.addIndexingParmeters( provider, indexingParams );
-  }
-
-  /**
-   * Returns an array of directory properties
-   * Properties are defaulted. For a given property name,
-   * hibernate.search.indexname.n has priority over hibernate.search.indexname which has priority over hibernate.search
-   * If the Index is not sharded, a single Properties is returned
-   * If the index is sharded, the Properties index matches the shard index
-   */  
-  private static Properties[] getDirectoryProperties(Configuration cfg, String directoryProviderName) {
-
-    Properties cfgAndImplicitProperties = new Properties();
-    // cfg has no defaults, so we may use keySet iteration
-    //FIXME not so sure about that cfg.setProperties()?
-    for ( Map.Entry entry : cfg.getProperties().entrySet() ) {
-      String key = entry.getKey().toString();// casting to String
-      if ( key.startsWith( LUCENE_PREFIX ) ) {
-        //put regular properties and add an explicit batch property when a transaction property is set
-        cfgAndImplicitProperties.put( key, entry.getValue() );
-        //be careful to replace only the intended ".transaction." with ".batch.":
-        String[] splitKey = dotPattern.split( key );
-        //TODO this code is vulnerable to properties with dot in the name. This is not a problem today though
-        if ( splitKey.length > 2 && splitKey[ splitKey.length - 2 ]
-                                 .equals( LuceneIndexingParameters.TRANSACTION ) ) {
-          splitKey[ splitKey.length - 2 ] = LuceneIndexingParameters.BATCH;
-          StringBuilder missingKeyBuilder = new StringBuilder( splitKey[0] );
-          for (int i = 1; i < splitKey.length; i++) {
-            missingKeyBuilder.append( "." );
-            missingKeyBuilder.append( splitKey[i] );
-          }
-          String additionalKey = missingKeyBuilder.toString();
-          if ( cfg.getProperty(additionalKey) == null ){
-            cfgAndImplicitProperties.put(additionalKey, cfg.getProperty(key) );
-          }
-        }
-      }
-    }
-    Properties globalProperties = new Properties();
-    Properties directoryLocalProperties = new Properties( globalProperties );
-    String directoryLocalPrefix = LUCENE_PREFIX + directoryProviderName + ".";
-    for ( Map.Entry entry : cfgAndImplicitProperties.entrySet() ) {
-      String key = entry.getKey().toString();// casting to String
-      if ( key.startsWith( LUCENE_DEFAULT ) ) {
-        globalProperties.put( key.substring( LUCENE_DEFAULT.length() ), entry.getValue() );
-      }
-      else if ( key.startsWith( directoryLocalPrefix ) ) {
-        directoryLocalProperties.put( key.substring( directoryLocalPrefix.length() ),entry.getValue() );
-      }
-    }
-    final String shardsCountValue = directoryLocalProperties.getProperty(NBR_OF_SHARDS);
-    if (shardsCountValue == null) {
-      // no shards: finished.
-      return new Properties[] { directoryLocalProperties };
-    } else {
-      // count shards
-      int shardsCount = -1;
-      {
-        try {
-          shardsCount = Integer.parseInt( shardsCountValue );
-        } catch (NumberFormatException e) {
-          if ( cfgAndImplicitProperties.getProperty(directoryLocalPrefix + NBR_OF_SHARDS ) != null)
-            throw new SearchException( shardsCountValue + " is not a number", e);
-        }
-      }
-      // create shard-specific Props
-      Properties[] shardLocalProperties = new Properties[shardsCount];
-      for ( int i = 0; i < shardsCount; i++ ) {
-        String currentShardPrefix = i + ".";
-        Properties currentProp = new Properties( directoryLocalProperties );
-        //Enumerations are ugly but otherwise we can't get the property defaults:
-        Enumeration<String> localProps = (Enumeration<String>) directoryLocalProperties.propertyNames();
-        while ( localProps.hasMoreElements() ){
-          String key = localProps.nextElement();
-          if ( key.startsWith( currentShardPrefix ) ) {
-            currentProp.setProperty( key.substring( currentShardPrefix.length() ), directoryLocalProperties.getProperty( key ) );
-          }
-        }
-        shardLocalProperties[i] = currentProp;
-      }
-      return shardLocalProperties;
-    }
-  }
-
-  private static String getDirectoryProviderName(XClass clazz, Configuration cfg) {
-    //yuk
-    ReflectionManager reflectionManager = SearchFactoryImpl.getReflectionManager(cfg);
-    //get the most specialized (ie subclass > superclass) non default index name
-    //if none extract the name from the most generic (superclass > subclass) @Indexed class in the hierarchy
-    //FIXME I'm inclined to get rid of the default value
-    PersistentClass pc = cfg.getClassMapping( clazz.getName() );
-    XClass rootIndex = null;
-    do {
-      XClass currentClazz = reflectionManager.toXClass( pc.getMappedClass() );
-      Indexed indexAnn = currentClazz.getAnnotation( Indexed.class );
-      if ( indexAnn != null ) {
-        if ( indexAnn.index().length() != 0 ) {
-          return indexAnn.index();
-        }
-        else {
-          rootIndex = currentClazz;
-        }
-      }
-      pc = pc.getSuperclass();
-    }
-    while ( pc != null );
-    //there is nobody out there with a non default @Indexed.index
-    if ( rootIndex != null ) {
-      return rootIndex.getName();
-    }
-    else {
-      throw new HibernateException(
-          "Trying to extract the index name from a non @Indexed class: " + clazz.getName() );
-    }
-  }
-
-  public class DirectoryProviders {
-    private IndexShardingStrategy shardingStrategy;
-    private DirectoryProvider[] providers;
-
-
-    public DirectoryProviders(IndexShardingStrategy shardingStrategy, DirectoryProvider[] providers) {
-      this.shardingStrategy = shardingStrategy;
-      this.providers = providers;
-    }
-
-
-    public IndexShardingStrategy getSelectionStrategy() {
-      return shardingStrategy;
-    }
-
-    public DirectoryProvider[] getProviders() {
-      return providers;
-    }
-  }
-}
+//$Id$
+package org.hibernate.search.store;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.hibernate.annotations.common.reflection.ReflectionManager;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.search.SearchException;
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.backend.LuceneIndexingParameters;
+import org.hibernate.search.backend.configuration.MaskedProperty;
+import org.hibernate.search.engine.SearchFactoryImplementor;
+import org.hibernate.search.impl.SearchFactoryImpl;
+import org.hibernate.search.store.optimization.IncrementalOptimizerStrategy;
+import org.hibernate.search.store.optimization.NoOpOptimizerStrategy;
+import org.hibernate.search.store.optimization.OptimizerStrategy;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Create a Lucene directory provider
+ * <p/>
+ * Lucene directory providers are configured through properties
+ * <ul>
+ *  <li>hibernate.search.default.* and</li>
+ *  <li>hibernate.search.&lt;indexname&gt;.*</li>
+ * </ul>
+ * <p/>
+ * &lt;indexname&gt; properties have precedence over default
+ * <p/>
+ * The implementation is described by
+ * hibernate.search.[default|indexname].directory_provider
+ * <p/>
+ * If none is defined the default value is FSDirectory
+ *
+ * @author Emmanuel Bernard
+ * @author Sylvain Vieujot
+ * @author Hardy Ferentschik
+ * @author Sanne Grinovero
+ */
+public class DirectoryProviderFactory {
+  
+  private List<DirectoryProvider<?>> providers = new ArrayList<DirectoryProvider<?>>();
+  private static String DEFAULT_DIRECTORY_PROVIDER = FSDirectoryProvider.class.getName();
+  
+  private static final String SHARDING_STRATEGY = "sharding_strategy";
+  private static final String NBR_OF_SHARDS = SHARDING_STRATEGY + ".nbr_of_shards";
+
+  public DirectoryProviders createDirectoryProviders(XClass entity, Configuration cfg, SearchFactoryImplementor searchFactoryImplementor) {
+    //get properties
+    String directoryProviderName = getDirectoryProviderName( entity, cfg );
+    Properties[] indexProps = getDirectoryProperties( cfg, directoryProviderName );
+
+    //set up the directories
+    int nbrOfProviders = indexProps.length;
+    DirectoryProvider[] providers = new DirectoryProvider[nbrOfProviders];
+    for ( int index = 0 ; index < nbrOfProviders ; index++ ) {
+      String providerName = nbrOfProviders > 1 ?
+          directoryProviderName + "." + index :
+          directoryProviderName;
+      providers[index] = createDirectoryProvider( providerName, indexProps[index], searchFactoryImplementor );
+    }
+
+    //define sharding strategy
+    IndexShardingStrategy shardingStrategy;
+    //any indexProperty will do, the indexProps[0] surely exists.
+    String shardingStrategyName = indexProps[0].getProperty( SHARDING_STRATEGY );
+    if ( shardingStrategyName == null) {
+      if ( indexProps.length == 1 ) {
+        shardingStrategy = new NotShardedStrategy();
+      }
+      else {
+        shardingStrategy = new IdHashShardingStrategy();
+      }
+    }
+    else {
+      try {
+        Class shardigStrategyClass = ReflectHelper.classForName( shardingStrategyName, this.getClass() );
+        shardingStrategy = (IndexShardingStrategy) shardigStrategyClass.newInstance();
+      }
+      catch (ClassNotFoundException e) {
+        throw new SearchException("Unable to find ShardingStrategy class " + shardingStrategyName + " for " + directoryProviderName, e);
+      }
+      catch (IllegalAccessException e) {
+        throw new SearchException("Unable to create instance of ShardingStrategy class " + shardingStrategyName
+            + " Be sure to have a no-arg constructor", e);
+      }
+      catch (InstantiationException e) {
+        throw new SearchException("Unable to create instance of ShardingStrategy class " + shardingStrategyName
+            + " Be sure to have a no-arg constructor", e);
+      }
+      catch (ClassCastException e) {
+        throw new SearchException("ShardingStrategy class does not implements DirecotryProviderShardingStrategy: "
+            + shardingStrategyName, e);
+      }
+    }
+    shardingStrategy.initialize(
+        new MaskedProperty( indexProps[0], SHARDING_STRATEGY ), providers );
+    return new DirectoryProviders( shardingStrategy, providers );
+  }
+
+  public void startDirectoryProviders() {
+    for ( DirectoryProvider provider : providers ) {
+      provider.start();
+    }
+  }
+
+  private DirectoryProvider<?> createDirectoryProvider(String directoryProviderName, Properties indexProps, SearchFactoryImplementor searchFactoryImplementor) {
+    String className = indexProps.getProperty( "directory_provider" );
+    if ( StringHelper.isEmpty( className ) ) {
+      className = DEFAULT_DIRECTORY_PROVIDER;
+    }
+    DirectoryProvider<?> provider;
+    try {
+      @SuppressWarnings( "unchecked" )
+      Class<DirectoryProvider> directoryClass = ReflectHelper.classForName(
+          className, DirectoryProviderFactory.class
+      );
+      provider = directoryClass.newInstance();
+    }
+    catch (Exception e) {
+      throw new SearchException( "Unable to instantiate directory provider: " + className, e );
+    }
+    try {
+      provider.initialize( directoryProviderName, indexProps, searchFactoryImplementor );
+    }
+    catch (Exception e) {
+      throw new SearchException( "Unable to initialize: " + directoryProviderName, e );
+    }
+    int index = providers.indexOf( provider );
+    if ( index != -1 ) {
+      //share the same Directory provider for the same underlying store
+      return providers.get( index );
+    }
+    else {
+      configureOptimizerStrategy( searchFactoryImplementor, indexProps, provider );
+      configureIndexingParameters( searchFactoryImplementor, indexProps, provider );
+      providers.add( provider );
+      if ( !searchFactoryImplementor.getLockableDirectoryProviders().containsKey( provider ) ) {
+        searchFactoryImplementor.getLockableDirectoryProviders().put( provider, new ReentrantLock() );
+      }
+      return provider;
+    }
+  }
+
+  private void configureOptimizerStrategy(SearchFactoryImplementor searchFactoryImplementor, Properties indexProps, DirectoryProvider<?> provider) {
+    boolean incremental = indexProps.containsKey( "optimizer.operation_limit.max" )
+        || indexProps.containsKey( "optimizer.transaction_limit.max" );
+    OptimizerStrategy optimizerStrategy;
+    if (incremental) {
+      optimizerStrategy = new IncrementalOptimizerStrategy();
+      optimizerStrategy.initialize( provider, indexProps, searchFactoryImplementor );
+    }
+    else {
+      optimizerStrategy = new NoOpOptimizerStrategy();
+    }
+    searchFactoryImplementor.addOptimizerStrategy( provider, optimizerStrategy );
+  }
+  
+  /**
+   * Creates a new <code>LuceneIndexingParameters</code> instance for the specified provider.
+   * If there are no matching properties in the configuration default values will be applied.
+   * <p>
+   * NOTE:</br>
+   * If a non batch value is set in the configuration apply it also to the
+   * batch mode. This covers the case where users only specify
+   * parameters for the non batch mode. In this case the same parameters apply for
+   * batch indexing. Parameters are found "depth-first": if a batch parameter is set
+   * in a global scope it will take priority on local transaction parameters.
+   * </p>
+   *
+   * @param searchFactoryImplementor the search factory.
+   * @param directoryProperties The properties extracted from the configuration.
+   * @param provider The directory provider for which to configure the indexing parameters.
+   */
+  private void configureIndexingParameters(SearchFactoryImplementor searchFactoryImplementor,
+      Properties directoryProperties, DirectoryProvider<?> provider) {
+    LuceneIndexingParameters indexingParams = new LuceneIndexingParameters( directoryProperties );
+    searchFactoryImplementor.addIndexingParmeters( provider, indexingParams );
+  }
+
+  /**
+   * Returns an array of directory properties
+   * Properties are defaulted. For a given property name,
+   * hibernate.search.indexname.n has priority over hibernate.search.indexname which has priority over hibernate.search.default
+   * If the Index is not sharded, a single Properties is returned
+   * If the index is sharded, the Properties index matches the shard index
+   */  
+  private static Properties[] getDirectoryProperties(Configuration cfg, String directoryProviderName) {
+    Properties rootCfg = new MaskedProperty( cfg.getProperties(), "hibernate.search" );
+    Properties globalProperties = new MaskedProperty( rootCfg, "default" );
+    Properties directoryLocalProperties = new MaskedProperty( rootCfg, directoryProviderName, globalProperties );
+    final String shardsCountValue = directoryLocalProperties.getProperty( NBR_OF_SHARDS );
+    if ( shardsCountValue == null ) {
+      // no shards: finished.
+      return new Properties[] { directoryLocalProperties };
+    } else {
+      // count shards
+      int shardsCount;
+      {
+        try {
+          shardsCount = Integer.parseInt( shardsCountValue );
+        } catch (NumberFormatException e) {
+            throw new SearchException( shardsCountValue + " is not a number", e);
+        }
+      }
+      // create shard-specific Props
+      Properties[] shardLocalProperties = new Properties[shardsCount];
+      for ( int i = 0; i < shardsCount; i++ ) {
+        shardLocalProperties[i] = new MaskedProperty(
+            directoryLocalProperties, Integer.toString(i), directoryLocalProperties );
+      }
+      return shardLocalProperties;
+    }
+  }
+
+  private static String getDirectoryProviderName(XClass clazz, Configuration cfg) {
+    //yuk
+    ReflectionManager reflectionManager = SearchFactoryImpl.getReflectionManager(cfg);
+    //get the most specialized (ie subclass > superclass) non default index name
+    //if none extract the name from the most generic (superclass > subclass) @Indexed class in the hierarchy
+    //FIXME I'm inclined to get rid of the default value
+    PersistentClass pc = cfg.getClassMapping( clazz.getName() );
+    XClass rootIndex = null;
+    do {
+      XClass currentClazz = reflectionManager.toXClass( pc.getMappedClass() );
+      Indexed indexAnn = currentClazz.getAnnotation( Indexed.class );
+      if ( indexAnn != null ) {
+        if ( indexAnn.index().length() != 0 ) {
+          return indexAnn.index();
+        }
+        else {
+          rootIndex = currentClazz;
+        }
+      }
+      pc = pc.getSuperclass();
+    }
+    while ( pc != null );
+    //there is nobody out there with a non default @Indexed.index
+    if ( rootIndex != null ) {
+      return rootIndex.getName();
+    }
+    else {
+      throw new SearchException(
+          "Trying to extract the index name from a non @Indexed class: " + clazz.getName() );
+    }
+  }
+
+  public class DirectoryProviders {
+    private IndexShardingStrategy shardingStrategy;
+    private DirectoryProvider[] providers;
+
+    public DirectoryProviders(IndexShardingStrategy shardingStrategy, DirectoryProvider[] providers) {
+      this.shardingStrategy = shardingStrategy;
+      this.providers = providers;
+    }
+
+    public IndexShardingStrategy getSelectionStrategy() {
+      return shardingStrategy;
+    }
+
+    public DirectoryProvider[] getProviders() {
+      return providers;
+    }
+  }
+
+}

Modified: search/trunk/src/test/org/hibernate/search/test/configuration/ConfigurationReadTestCase.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/configuration/ConfigurationReadTestCase.java  2008-05-23 21:42:40 UTC (rev 14689)
+++ search/trunk/src/test/org/hibernate/search/test/configuration/ConfigurationReadTestCase.java  2008-05-26 23:04:52 UTC (rev 14690)
@@(protected) @@
import org.hibernate.search.engine.SearchFactoryImplementor;
import org.hibernate.search.impl.SearchFactoryImpl;
import org.hibernate.search.test.SearchTestCase;
+import org.hibernate.search.util.FileHelper;

/**
* Contains some utility methods to simplify coding of
@@(protected) @@
*/
public abstract class ConfigurationReadTestCase extends SearchTestCase {
 
-  private static final File INDEX_DIR = new File( new File("."), "indextemp" );
+  private static final File INDEX_DIR = new File( new File( "." ), "indextemp" );

 private SearchFactoryImplementor searchFactory;

@@(protected) @@
   FullTextSession fullTextSession = Search.createFullTextSession( openSession() );
   searchFactory = (SearchFactoryImpl) fullTextSession.getSearchFactory();
   fullTextSession.close();
-    remove(INDEX_DIR);
+    FileHelper.delete( INDEX_DIR );
   INDEX_DIR.mkdirs();
 }

@@(protected) @@
 
 protected void tearDown() throws Exception {
   super.tearDown();
-    remove(INDEX_DIR);
+    FileHelper.delete( INDEX_DIR );
 }
-  
-  private void remove(File indexDir) {
-    if (indexDir.exists()) {
-      File[] containing = indexDir.listFiles();
-      if ( containing != null ) { //is a directory
-        for (int i=0; i<containing.length; i++ ){
-          remove(containing[i]);
-        }
-      }
-      indexDir.delete();
-    }
-  }

}

Modified: search/trunk/src/test/org/hibernate/search/test/configuration/LuceneIndexingParametersTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/configuration/LuceneIndexingParametersTest.java  2008-05-23 21:42:40 UTC (rev 14689)
+++ search/trunk/src/test/org/hibernate/search/test/configuration/LuceneIndexingParametersTest.java  2008-05-26 23:04:52 UTC (rev 14690)
@@(protected) @@
   
   cfg.setProperty( "hibernate.search.Book.batch.max_merge_docs", "12" );
   cfg.setProperty( "hibernate.search.Book.batch.merge_factor", "13" );
-    cfg.setProperty( "hibernate.search.Book.batch.max_buffered_docs", "14" );
+    // new keyword "indexwriter" is also supported to group parameters:
+    cfg.setProperty( "hibernate.search.Book.indexwriter.batch.max_buffered_docs", "14" );
   
-    cfg.setProperty( "hibernate.search.Book.transaction.ram_buffer_size", "4" );
+    cfg.setProperty( "hibernate.search.Book.indexwriter.transaction.ram_buffer_size", "4" );
   cfg.setProperty( "hibernate.search.Book.transaction.max_merge_docs", "15" );
   cfg.setProperty( "hibernate.search.Book.transaction.merge_factor", "16" );
   cfg.setProperty( "hibernate.search.Book.transaction.max_buffered_docs", "17" );
@@(protected) @@
 
 public void testUnsetBatchValueTakesTransaction() throws Exception {
   assertValueIsSet( Document.class, BATCH, MERGE_FACTOR, 6 );
-    assertValueIsSet( Document.class, BATCH, MAX_BUFFERED_DOCS, 7 );
+    assertValueIsSet( Document.class, BATCH, MAX_BUFFERED_DOCS, 1000 );
 }
 
 public void testExplicitBatchParameters() throws Exception {
@@(protected) @@
 }
 
 public void testInheritedBatchParametersFromTranscation() throws Exception {
-    assertValueIsSet( Book.class, BATCH, RAM_BUFFER_SIZE, 4 );
+    assertValueIsSet( Book.class, BATCH, RAM_BUFFER_SIZE, 1 );
 }
 
 public void testTransactionParameters() throws Exception {

Added: search/trunk/src/test/org/hibernate/search/test/configuration/MaskedPropertiesTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/configuration/MaskedPropertiesTest.java                  (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/configuration/MaskedPropertiesTest.java  2008-05-26 23:04:52 UTC (rev 14690)
@@(protected) @@
+package org.hibernate.search.test.configuration;
+
+import java.util.Properties;
+
+import org.hibernate.search.backend.configuration.MaskedProperty;
+
+/**
+ * @author Sanne Grinovero
+ */
+public class MaskedPropertiesTest extends junit.framework.TestCase {
+
+  public void testConfigurationParsingPrecedence() {
+    Properties cfg = new Properties();
+    cfg.put( "hibernate.search.Animals.transaction.indexwriter.max_merge_docs", "1" );
+    cfg.put( "hibernate.search.Animals.2.transaction.indexwriter.max_merge_docs", "2" );
+    cfg.put( "hibernate.search.Animals.2.transaction.max_merge_docs", "3" );
+    cfg.put( "hibernate.search.Animals.transaction.max_merge_docs", "5" );
+    cfg.put( "hibernate.search.default.transaction.max_merge_docs", "6" );
+    cfg.put( "hibernate.search.default.transaction.indexwriter.max_field_length", "7" );
+
+    //this is more a "concept demo" than a test:
+    Properties root = new MaskedProperty( cfg, "hibernate.search" );
+    //only keys starting as "hibernate.search.default" are exposed:
+    Properties common = new MaskedProperty( root, "default" );
+    //now as "hibernate.search.Animals" or "hibernate.search.default" if first fails:
+    Properties dirProvider = new MaskedProperty( root, "Animals", common );
+    //this narrows visibility to "hibernate.search.<providername|default>.transaction":
+    Properties transaction = new MaskedProperty( dirProvider, "transaction" );
+    Properties shard2 = new MaskedProperty( dirProvider, "2", dirProvider );
+    Properties transactionInShard2 = new MaskedProperty( shard2, "transaction", transaction );
+    Properties newStyleTransaction = new MaskedProperty( transaction, "indexwriter", transaction );
+    Properties newStyleTransactionInShard2 = new MaskedProperty(
+        transactionInShard2, "indexwriter", transactionInShard2 );
+    
+    assertEquals( "7" , newStyleTransaction.getProperty( "max_field_length" ) );
+    assertEquals( "7" , newStyleTransactionInShard2.getProperty( "max_field_length" ) );
+    assertEquals( "5" , transaction.getProperty( "max_merge_docs" ) );
+  }
+  
+}

Modified: search/trunk/src/test/org/hibernate/search/test/configuration/ShardsConfigurationTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/configuration/ShardsConfigurationTest.java  2008-05-23 21:42:40 UTC (rev 14689)
+++ search/trunk/src/test/org/hibernate/search/test/configuration/ShardsConfigurationTest.java  2008-05-26 23:04:52 UTC (rev 14690)
@@(protected) @@
import static org.hibernate.search.backend.configuration.IndexWriterSetting.MAX_MERGE_DOCS;
import static org.hibernate.search.backend.configuration.IndexWriterSetting.MERGE_FACTOR;
import static org.hibernate.search.backend.configuration.IndexWriterSetting.RAM_BUFFER_SIZE;
+import static org.hibernate.search.backend.configuration.IndexWriterSetting.TERM_INDEX_INTERVAL;
import static org.hibernate.search.test.configuration.ConfigurationReadTestCase.TransactionType.TRANSACTION;
import static org.hibernate.search.test.configuration.ConfigurationReadTestCase.TransactionType.BATCH;
import org.hibernate.search.store.DirectoryProvider;
@@(protected) @@
   cfg.setProperty( "hibernate.search.Documents.0.transaction.max_buffered_docs", "58" );
   cfg.setProperty( "hibernate.search.Documents.1.batch.max_merge_docs", "11" );
   cfg.setProperty( "hibernate.search.Documents.1.transaction.max_buffered_docs", "12" );
+    cfg.setProperty( "hibernate.search.Documents.1.transaction.term_index_interval", "12" );
 }
 
 public void testCorrectNumberOfShardsDetected() throws Exception {
-    DirectoryProvider[] docDirProviders = getSearchFactory().getDirectoryProviders(Document.class);
-    assertNotNull(docDirProviders);
-    assertEquals(4, docDirProviders.length);
-    DirectoryProvider[] bookDirProviders = getSearchFactory().getDirectoryProviders(Book.class);
-    assertNotNull(bookDirProviders);
-    assertEquals(2, bookDirProviders.length);
+    DirectoryProvider[] docDirProviders = getSearchFactory()
+      .getDirectoryProviders( Document.class );
+    assertNotNull( docDirProviders);
+    assertEquals( 4, docDirProviders.length );
+    DirectoryProvider[] bookDirProviders = getSearchFactory()
+      .getDirectoryProviders( Book.class );
+    assertNotNull( bookDirProviders );
+    assertEquals( 2, bookDirProviders.length );
 }
 
 public void testSelectionOfShardingStrategy() throws Exception {
-    IndexShardingStrategy shardingStrategy = getSearchFactory().getDocumentBuilders().get(Document.class).getDirectoryProviderSelectionStrategy();
+    IndexShardingStrategy shardingStrategy = getSearchFactory().getDocumentBuilders()
+      .get( Document.class ).getDirectoryProviderSelectionStrategy();
   assertNotNull( shardingStrategy );
   assertEquals( shardingStrategy.getClass(), UselessShardingStrategy.class );
 }
 
 public void testShardingSettingsInherited() throws Exception {
-    DirectoryProvider[] docDirProviders = getSearchFactory().getDirectoryProviders(Document.class);
+    DirectoryProvider[] docDirProviders = getSearchFactory().getDirectoryProviders( Document.class );
   assertTrue( docDirProviders[0] instanceof RAMDirectoryProvider );
   assertTrue( docDirProviders[1] instanceof FSDirectoryProvider );
   assertTrue( docDirProviders[2] instanceof RAMDirectoryProvider );
 }
 
 public void testShardN2UsesDefaults() throws Exception {
-    assertValueIsSet( Document.class, 2, TRANSACTION, MAX_BUFFERED_DOCS, 6);
+    assertValueIsSet( Document.class, 2, TRANSACTION, MAX_BUFFERED_DOCS, 6 );
   assertValueIsDefault( Document.class, 2, TRANSACTION, MAX_MERGE_DOCS );
   assertValueIsSet( Document.class, 2, TRANSACTION, MERGE_FACTOR, 100 );
   assertValueIsDefault( Document.class, 2, TRANSACTION, RAM_BUFFER_SIZE );
@@(protected) @@
 }
 
 public void testShard_BatchInheritedFromTransaction() throws Exception {
-    assertValueIsSet( Document.class, 1, BATCH, MAX_BUFFERED_DOCS, 12 );
-    assertValueIsSet( Document.class, 0, BATCH, MAX_BUFFERED_DOCS, 58 );
+    assertValueIsSet( Document.class, 1, BATCH, TERM_INDEX_INTERVAL, 12 );
+    assertValueIsSet( Document.class, 0, BATCH, MAX_BUFFERED_DOCS, 4 );
 }
 
 protected Class[] getMappings() {

_______________________________________________
hibernate-commits mailing list
hibernate-commits@(protected)
https://lists.jboss.org/mailman/listinfo/hibernate-commits
©2008 gg3721.com - Jax Systems, LLC, U.S.A.