Package org.hibernate.search.event

Source Code of org.hibernate.search.event.FullTextIndexEventListener

//$Id: FullTextIndexEventListener.java 10865 2006-11-23 23:30:01 +0100 (jeu., 23 nov. 2006) epbernard $
package org.hibernate.search.event;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.locks.ReentrantLock;
import javax.transaction.Status;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.hibernate.HibernateException;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.hibernate.event.AbstractEvent;
import org.hibernate.event.Initializable;
import org.hibernate.event.PostDeleteEvent;
import org.hibernate.event.PostDeleteEventListener;
import org.hibernate.event.PostInsertEvent;
import org.hibernate.event.PostInsertEventListener;
import org.hibernate.event.PostUpdateEvent;
import org.hibernate.event.PostUpdateEventListener;
import org.hibernate.search.Environment;
import org.hibernate.search.util.WeakIdentityHashMap;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.backend.AddWork;
import org.hibernate.search.backend.DeleteWork;
import org.hibernate.search.backend.UpdateWork;
import org.hibernate.search.backend.Work;
import org.hibernate.search.backend.WorkQueue;
import org.hibernate.search.backend.impl.BatchLuceneWorkQueue;
import org.hibernate.search.backend.impl.PostTransactionWorkQueueSynchronization;
import org.hibernate.search.engine.DocumentBuilder;
import org.hibernate.search.store.DirectoryProvider;
import org.hibernate.search.store.DirectoryProviderFactory;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.reflection.ReflectionManager;
import org.hibernate.reflection.XClass;
import org.hibernate.util.ReflectHelper;

/**
* This listener supports setting a parent directory for all generated index files.
* It also supports setting the analyzer class to be used.
*
* @author Gavin King
* @author Emmanuel Bernard
* @author Mattias Arbin
*/
//TODO work on sharing the same indexWriters and readers across a single post operation...
//TODO implement and use a LockableDirectoryProvider that wraps a DP to handle the lock inside the LDP
public class FullTextIndexEventListener implements PostDeleteEventListener, PostInsertEventListener,
    PostUpdateEventListener, Initializable {
  protected ReflectionManager reflectionManager;
  //not a synchronized map since for a given transaction, we have not concurrent access
  protected WeakIdentityHashMap queuePerTransaction;

  //FIXME keeping this here is a bad decision since you might want to search indexes wo maintain it
  @Deprecated
  public Map<Class, DocumentBuilder<Object>> getDocumentBuilders() {
    return documentBuilders;
  }


  private Map<Class, DocumentBuilder<Object>> documentBuilders = new HashMap<Class, DocumentBuilder<Object>>();
  //keep track of the index modifiers per DirectoryProvider since multiple entity can use the same directory provider
  private Map<DirectoryProvider, ReentrantLock> lockableDirectoryProviders =
      new HashMap<DirectoryProvider, ReentrantLock>();
  private boolean initialized;

  private static final Log log = LogFactory.getLog( FullTextIndexEventListener.class );

  public void initialize(Configuration cfg) {
    if ( initialized ) return;
    //yuk
    reflectionManager = ( (AnnotationConfiguration) cfg ).createExtendedMappings().getReflectionManager();
    queuePerTransaction = new WeakIdentityHashMap();

    Class analyzerClass;
    String analyzerClassName = cfg.getProperty( Environment.ANALYZER_CLASS );
    if ( analyzerClassName != null ) {
      try {
        analyzerClass = ReflectHelper.classForName( analyzerClassName );
      }
      catch (Exception e) {
        throw new HibernateException(
            "Lucene analyzer class '" + analyzerClassName + "' defined in property '" + Environment.ANALYZER_CLASS + "' could not be found.",
            e
        );
      }
    }
    else {
      analyzerClass = StandardAnalyzer.class;
    }
    // Initialize analyzer
    Analyzer analyzer;
    try {
      analyzer = (Analyzer) analyzerClass.newInstance();
    }
    catch (ClassCastException e) {
      throw new HibernateException(
          "Lucene analyzer does not implement " + Analyzer.class.getName() + ": " + analyzerClassName
      );
    }
    catch (Exception e) {
      throw new HibernateException( "Failed to instantiate lucene analyzer with type " + analyzerClassName );
    }

    Iterator iter = cfg.getClassMappings();
    DirectoryProviderFactory factory = new DirectoryProviderFactory();
    while ( iter.hasNext() ) {
      PersistentClass clazz = (PersistentClass) iter.next();
      Class<?> mappedClass = clazz.getMappedClass();
      if ( mappedClass != null ) {
        XClass mappedXClass = reflectionManager.toXClass( mappedClass );
        if ( mappedXClass != null && mappedXClass.isAnnotationPresent( Indexed.class ) ) {
          DirectoryProvider provider = factory.createDirectoryProvider( mappedXClass, cfg );
          if ( !lockableDirectoryProviders.containsKey( provider ) ) {
            lockableDirectoryProviders.put( provider, new ReentrantLock() );
          }
          final DocumentBuilder<Object> documentBuilder = new DocumentBuilder<Object>(
              mappedXClass, analyzer, provider, reflectionManager
          );

          documentBuilders.put( mappedClass, documentBuilder );
        }
      }
    }
    Set<Class> indexedClasses = documentBuilders.keySet();
    for ( DocumentBuilder builder : documentBuilders.values() ) {
      builder.postInitialize( indexedClasses );
    }
    initialized = true;
  }

  public void onPostDelete(PostDeleteEvent event) {
    if ( documentBuilders.containsKey( event.getEntity().getClass() ) ) {
      DeleteWork work = new DeleteWork( event.getId(), event.getEntity().getClass() );
      processWork( work, event );
    }
  }

  public void onPostInsert(PostInsertEvent event) {
    final Object entity = event.getEntity();
    DocumentBuilder<Object> builder = documentBuilders.get( entity.getClass() );
    if ( builder != null ) {
      Serializable id = event.getId();
      Document doc = builder.getDocument( entity, id );
      AddWork work = new AddWork( id, entity.getClass(), doc );
      processWork( work, event );
    }
  }

  public void onPostUpdate(PostUpdateEvent event) {
    final Object entity = event.getEntity();
    DocumentBuilder<Object> builder = documentBuilders.get( entity.getClass() );
    if ( builder != null ) {
      Serializable id = event.getId();
      Document doc = builder.getDocument( entity, id );
      UpdateWork work = new UpdateWork( id, entity.getClass(), doc );
      processWork( work, event );
    }
  }

  private void processWork(Work work, AbstractEvent event) {
    if ( event.getSession().isTransactionInProgress() ) {
      Transaction transaction = event.getSession().getTransaction();
      PostTransactionWorkQueueSynchronization sync = (PostTransactionWorkQueueSynchronization)
          queuePerTransaction.get( transaction );
      if ( sync == null || sync.isConsumed() ) {
        WorkQueue workQueue = new BatchLuceneWorkQueue( documentBuilders, lockableDirectoryProviders );
        sync = new PostTransactionWorkQueueSynchronization( workQueue, queuePerTransaction );
        transaction.registerSynchronization( sync );
        queuePerTransaction.put(transaction, sync);
      }
      sync.add( work );
    }
    else {
      WorkQueue workQueue = new BatchLuceneWorkQueue( documentBuilders, lockableDirectoryProviders );
      PostTransactionWorkQueueSynchronization sync = new PostTransactionWorkQueueSynchronization( workQueue );
      sync.add( work );
      sync.afterCompletion( Status.STATUS_COMMITTED );
    }
  }

  public Map<DirectoryProvider, ReentrantLock> getLockableDirectoryProviders() {
    return lockableDirectoryProviders;
  }
}
TOP

Related Classes of org.hibernate.search.event.FullTextIndexEventListener

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.