Package org.hibernate.search.store

Source Code of org.hibernate.search.store.DirectoryProviderFactory$DirectoryProviders

//$Id: DirectoryProviderFactory.java 13945 2007-08-21 18:01:54Z epbernard $
package org.hibernate.search.store;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.locks.ReentrantLock;

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
*/
@SuppressWarnings("unchecked")
public class DirectoryProviderFactory {
  public 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();
 
  // Lucene index performance parameters
  private static final String MERGE_FACTOR = "merge_factor";
  private static final String MAX_MERGE_DOCS = "max_merge_docs";
  private static final String MAX_BUFFERED_DOCS = "max_buffered_docs";
  private static final String BATCH = "batch.";
  private static final String TRANSACTION = "transaction.";

  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;
    Properties shardingProperties = new Properties();
    /***********hibernate search code**********
    for (Map.Entry entry : indexProps[0].entrySet()) {
      if ( ( (String) entry.getKey() ).startsWith( SHARDING_STRATEGY ) ) {
        shardingProperties.put( entry.getKey(), entry.getValue() );
      }
    }
    ******************************************/
   
    /****************changed by Jerry*************/
    for (String key : indexProps[0].stringPropertyNames()) {
      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 {
      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
   * paramters 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 direcotry provider for which to configure the indexing parameters.
   */
  private void configureIndexingParameters(SearchFactoryImplementor searchFactoryImplementor, Properties indexProps, DirectoryProvider<?> provider) {
   
    LuceneIndexingParameters indexingParams = new LuceneIndexingParameters();
    String s = indexProps.getProperty(TRANSACTION + MERGE_FACTOR);
   
    if (!StringHelper.isEmpty( s )) {
      try{
        indexingParams.setTransactionMergeFactor(Integer.valueOf(s));
        indexingParams.setBatchMergeFactor(Integer.valueOf(s));
      } catch (NumberFormatException ne) {
        throw new SearchException("Invalid value for " + TRANSACTION + MERGE_FACTOR + ": " + s);
      }
    }

    s = indexProps.getProperty(TRANSACTION + MAX_MERGE_DOCS);
    if (!StringHelper.isEmpty( s )) {
      try{
        indexingParams.setTransactionMaxMergeDocs(Integer.valueOf(s));
        indexingParams.setBatchMaxMergeDocs(Integer.valueOf(s));
      } catch (NumberFormatException ne) {
        throw new SearchException("Invalid value for " + TRANSACTION + MAX_MERGE_DOCS + ": " + s);
      }
    }
   
    s = indexProps.getProperty(TRANSACTION + MAX_BUFFERED_DOCS);
    if (!StringHelper.isEmpty( s )) {
      try{
        indexingParams.setTransactionMaxBufferedDocs(Integer.valueOf(s));
        indexingParams.setBatchMaxBufferedDocs(Integer.valueOf(s));
      } catch (NumberFormatException ne) {
        throw new SearchException("Invalid value for " + TRANSACTION + MAX_BUFFERED_DOCS + ": " + s);
      }
    }   
       
    s = indexProps.getProperty(BATCH + MERGE_FACTOR);
    if (!StringHelper.isEmpty( s )) {
      try{
        indexingParams.setBatchMergeFactor(Integer.valueOf(s));
      } catch (NumberFormatException ne) {
        throw new SearchException("Invalid value for " + BATCH + MERGE_FACTOR + ": " + s);
      }
    }
   
    s = indexProps.getProperty(BATCH + MAX_MERGE_DOCS);
    if (!StringHelper.isEmpty( s )) {
      try{
        indexingParams.setBatchMaxMergeDocs(Integer.valueOf(s));
      } catch (NumberFormatException ne) {
        throw new SearchException("Invalid value for " + BATCH + MAX_MERGE_DOCS + ": " + s);
      }
    }
   
    s = indexProps.getProperty(BATCH + MAX_BUFFERED_DOCS);
    if (!StringHelper.isEmpty( s )) {
      try{
        indexingParams.setBatchMaxBufferedDocs(Integer.valueOf(s));
      } catch (NumberFormatException ne) {
        throw new SearchException("Invalid value for " + BATCH + MAX_BUFFERED_DOCS + ": " + s);
      }
    } 
    searchFactoryImplementor.addIndexingParmeters(provider, indexingParams);
  }

  /**
   * Returns an array of directory properties
   * Properties are defaulted. For a given proeprty 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 props = cfg.getProperties();
    String indexName = LUCENE_PREFIX + directoryProviderName;
    //indexSpecificProperties[i] >> indexSpecificDefaultproperties >> defaultProperties
    Properties defaultProperties = new Properties();
    ArrayList<Properties> indexSpecificProps = new ArrayList<Properties>();
    Properties indexSpecificDefaultProps = new Properties(defaultProperties);
    for ( Map.Entry entry : props.entrySet() ) {
      String key = (String) entry.getKey();
      if ( key.startsWith( LUCENE_DEFAULT ) ) {
        defaultProperties.setProperty( key.substring( LUCENE_DEFAULT.length() ), (String) entry.getValue() );
      }
      else if ( key.startsWith( indexName ) ) {
        String suffixedKey = key.substring( indexName.length() + 1 );
        int nextDoc = suffixedKey.indexOf( '.' );
        int index = -1;
        if ( nextDoc != -1 ) {
            String potentialNbr = suffixedKey.substring( 0, nextDoc );
          try {
            index = Integer.parseInt( potentialNbr );
          }
          catch ( Exception e ) {
            //just not a number
            index = -1;
          }
        }
        if (index == -1) {
          indexSpecificDefaultProps.setProperty( suffixedKey, (String) entry.getValue() );
        }
        else {
          String finalKeyName = suffixedKey.substring( nextDoc + 1 );
          //ignore sharding strategy properties
          if ( ! finalKeyName.startsWith( SHARDING_STRATEGY ) ) {
            ensureListSize( indexSpecificProps, index + 1 );
            Properties propertiesforIndex = indexSpecificProps.get( index );
            if ( propertiesforIndex == null ) {
              propertiesforIndex = new Properties( indexSpecificDefaultProps );
              indexSpecificProps.set( index, propertiesforIndex );
            }
            propertiesforIndex.setProperty( finalKeyName, (String) entry.getValue() );
          }
        }
      }
    }
    String nbrOfShardsString = indexSpecificDefaultProps.getProperty( NBR_OF_SHARDS );
    int nbrOfShards = -1;
    if ( nbrOfShardsString != null ) {
      try {
        nbrOfShards = Integer.parseInt( nbrOfShardsString );
      }
      catch (NumberFormatException e) {
        throw new SearchException(indexName + "." + NBR_OF_SHARDS + " is not a number", e);
      }
    }
    if ( nbrOfShards <= 0 && indexSpecificProps.size() == 0 ) {
      //no shard (a shareded subindex has to have at least one property
      return new Properties[] { indexSpecificDefaultProps };
    }
    else {
      //sharded
      nbrOfShards = nbrOfShards >= indexSpecificDefaultProps.size() ?
          nbrOfShards :
          indexSpecificDefaultProps.size();
      ensureListSize( indexSpecificProps, nbrOfShards );
      for ( int index = 0 ; index < nbrOfShards ; index++ ) {
        if ( indexSpecificProps.get( index ) == null ) {
          indexSpecificProps.set( index, new Properties( indexSpecificDefaultProps ) );
        }
      }
      return indexSpecificProps.toArray( new Properties[ indexSpecificProps.size() ] );
    }
  }

  private static void ensureListSize(ArrayList<Properties> indexSpecificProps, int size) {
    //ensure the index exists
    indexSpecificProps.ensureCapacity( size );
    while ( indexSpecificProps.size() < size ) {
      indexSpecificProps.add(null);
    }
  }

  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;
    }
  }
}
TOP

Related Classes of org.hibernate.search.store.DirectoryProviderFactory$DirectoryProviders

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.