/* * Hibernate Search, full-text search for your domain model * * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.search.test.util; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import org.apache.lucene.analysis.core.StopAnalyzer; import org.hibernate.Session; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventType; import org.hibernate.event.spi.LoadEventListener; import org.hibernate.internal.SessionFactoryImpl; import org.hibernate.search.FullTextSession; import org.hibernate.search.Search; import org.hibernate.search.SearchFactory; import org.hibernate.search.cfg.SearchMapping; import org.hibernate.search.hcore.util.impl.ContextHelper; import org.hibernate.search.impl.ImplementationFactory; import org.hibernate.search.testsupport.TestConstants; import org.hibernate.search.util.impl.FileHelper; import org.hibernate.search.util.logging.impl.Log; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.testing.cache.CachingRegionFactory; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; /** * Use the builder pattern to provide a SessionFactory. * This is meant to use only ram-based index and databases, for those test * which need to use several differently configured SessionFactories. * * @author Sanne Grinovero * @author Hardy Ferentschik */ public class FullTextSessionBuilder implements AutoCloseable, TestRule { private static final Log log = org.hibernate.search.util.logging.impl.LoggerFactory.make(); private File indexRootDirectory; private final Properties cfg = new Properties(); private final Set<Class<?>> annotatedClasses = new HashSet<Class<?>>(); private SessionFactoryImplementor sessionFactory; private boolean usingFileSystem = false; private final List<LoadEventListener> additionalLoadEventListeners = new ArrayList<LoadEventListener>(); public FullTextSessionBuilder() { cfg.setProperty( "hibernate.search.lucene_version", TestConstants.getTargetLuceneVersion().toString() ); cfg.setProperty( Environment.HBM2DDL_AUTO, "create-drop" ); //cache: cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" ); cfg.setProperty( Environment.CACHE_REGION_FACTORY, CachingRegionFactory.class.getCanonicalName() ); cfg.setProperty( Environment.USE_QUERY_CACHE, "true" ); //search specific: cfg.setProperty( org.hibernate.search.cfg.Environment.ANALYZER_CLASS, StopAnalyzer.class.getName() ); cfg.setProperty( "hibernate.search.default.directory_provider", "ram" ); usingFileSystem = false; } /** * Store indexes permanently in FSDirectory. Helper to automatically cleanup * the filesystem when the builder is closed; alternatively you could just use * properties directly and clean the filesystem explicitly. * * @param testClass needed to locate an appropriate temporary directory * @return the same builder (this). */ public FullTextSessionBuilder useFileSystemDirectoryProvider(Class<?> testClass) { indexRootDirectory = new File( TestConstants.getIndexDirectory( TestConstants.getTempTestDataDir() ) ); log.debugf( "Using %s as index directory.", indexRootDirectory.getAbsolutePath() ); cfg.setProperty( "hibernate.search.default.directory_provider", "filesystem" ); cfg.setProperty( "hibernate.search.default.indexBase", indexRootDirectory.getAbsolutePath() ); usingFileSystem = true; return this; } /** * Override before building any parameter, or add new ones. * * @param key Property name. * @param value Property value. * * @return the same builder (this). */ public FullTextSessionBuilder setProperty(String key, String value) { cfg.setProperty( key, value ); return this; } /** * Adds classes to the SessionFactory being built. * * @param annotatedClass The annotated class to add to the configuration. * * @return the same builder (this) */ public FullTextSessionBuilder addAnnotatedClass(Class annotatedClass) { annotatedClasses.add( annotatedClass ); return this; } /** * @return a new FullTextSession based upon the built configuration. */ public FullTextSession openFullTextSession() { if ( sessionFactory == null ) { build(); } Session session = sessionFactory.openSession(); return Search.getFullTextSession( session ); } /** * Closes the SessionFactory. * Make sure you close all sessions first */ @Override public void close() { if ( sessionFactory == null ) { throw new java.lang.IllegalStateException( "sessionFactory not yet built" ); } try { sessionFactory.close(); } finally { if ( usingFileSystem ) { try { cleanupFilesystem(); } catch (IOException e) { throw new RuntimeException( e ); } } } sessionFactory = null; } /** * Builds the sessionFactory as configured so far. */ public FullTextSessionBuilder build() { final Configuration hibConfiguration = buildBaseConfiguration(); for ( Class<?> annotatedClass : annotatedClasses ) { hibConfiguration.addAnnotatedClass( annotatedClass ); } hibConfiguration.getProperties().putAll( cfg ); StandardServiceRegistry serviceRegistry = buildServiceRegistry( cfg ); SessionFactoryImpl sessionFactoryImpl = (SessionFactoryImpl) hibConfiguration.buildSessionFactory( serviceRegistry ); ServiceRegistryImplementor serviceRegistryImplementor = sessionFactoryImpl.getServiceRegistry(); EventListenerRegistry registry = serviceRegistryImplementor.getService( EventListenerRegistry.class ); for ( LoadEventListener listener : additionalLoadEventListeners ) { registry.getEventListenerGroup( EventType.LOAD ).appendListener( listener ); } sessionFactory = sessionFactoryImpl; return this; } private StandardServiceRegistry buildServiceRegistry(Properties settings) { return new StandardServiceRegistryBuilder().applySettings( settings ).build(); } private Configuration buildBaseConfiguration() { Configuration configuration = new Configuration(); configuration.setProperty( AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true" ); //As in ORM testsuite return configuration; } /** * @return the SearchFactory */ public SearchFactory getSearchFactory() { if ( sessionFactory == null ) { build(); } return ImplementationFactory.createSearchFactory( ContextHelper.getSearchIntegratorBySFI( sessionFactory ) ); } /** * Defines a programmatic configuration to be used by Search * * @return the enabled SearchMapping. change it to define the mapping programmatically. */ public SearchMapping fluentMapping() { SearchMapping mapping = (SearchMapping) cfg.get( org.hibernate.search.cfg.Environment.MODEL_MAPPING ); if ( mapping == null ) { mapping = new SearchMapping(); cfg.put( org.hibernate.search.cfg.Environment.MODEL_MAPPING, mapping ); } return mapping; } public void cleanupFilesystem() throws IOException { FileHelper.delete( indexRootDirectory ); } public FullTextSessionBuilder addLoadEventListener(LoadEventListener additionalLoadEventListener) { additionalLoadEventListeners.add( additionalLoadEventListener ); return this; } @Override public Statement apply(final Statement base, Description description) { return new Statement() { @Override public void evaluate() throws Throwable { build(); try { base.evaluate(); } finally { close(); } } }; } }