/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* JBoss, Home of Professional Open Source
* Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package org.hibernate.search.indexes.impl;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.Similarity;
import org.hibernate.search.backend.BackendFactory;
import org.hibernate.search.backend.IndexingMonitor;
import org.hibernate.search.backend.LuceneWork;
import org.hibernate.search.backend.OptimizeLuceneWork;
import org.hibernate.search.backend.spi.BackendQueueProcessor;
import org.hibernate.search.backend.spi.LuceneIndexingParameters;
import org.hibernate.search.engine.ServiceManager;
import org.hibernate.search.engine.impl.EmptyBuildContext;
import org.hibernate.search.engine.spi.EntityIndexBinder;
import org.hibernate.search.engine.spi.SearchFactoryImplementor;
import org.hibernate.search.indexes.serialization.spi.LuceneWorkSerializer;
import org.hibernate.search.indexes.serialization.spi.SerializerService;
import org.hibernate.search.indexes.spi.DirectoryBasedReaderProvider;
import org.hibernate.search.indexes.spi.IndexManager;
import org.hibernate.search.indexes.spi.ReaderProvider;
import org.hibernate.search.spi.WorkerBuildContext;
import org.hibernate.search.store.DirectoryProvider;
import org.hibernate.search.store.impl.DirectoryProviderFactory;
import org.hibernate.search.store.optimization.OptimizerStrategy;
import org.hibernate.search.util.logging.impl.Log;
import org.hibernate.search.util.logging.impl.LoggerFactory;
/**
* This implementation of IndexManager is coupled to a
* DirectoryProvider and a DirectoryBasedReaderProvider
*
* @author Sanne Grinovero <sanne@hibernate.org> (C) 2011 Red Hat Inc.
*/
public class DirectoryBasedIndexManager implements IndexManager {
private static Log log = LoggerFactory.make();
private String indexName;
private DirectoryProvider directoryProvider;
private Similarity similarity;
private BackendQueueProcessor backend;
private OptimizerStrategy optimizer;
private LuceneIndexingParameters indexingParameters;
private final Set<Class<?>> containedEntityTypes = new HashSet<Class<?>>();
private LuceneWorkSerializer serializer;
private SearchFactoryImplementor boundSearchFactory = null;
private DirectoryBasedReaderProvider readers = null;
private IndexWriterConfig writerConfig;
private ServiceManager serviceManager;
@Override
public String getIndexName() {
return indexName;
}
@Override
public ReaderProvider getReaderProvider() {
return readers;
}
@Override
public void destroy() {
readers.stop();
backend.close();
directoryProvider.stop();
if ( serializer != null ) {
serviceManager.releaseService( SerializerService.class );
}
}
@Override
public void initialize(String indexName, Properties cfg, WorkerBuildContext buildContext) {
this.indexName = indexName;
directoryProvider = createDirectoryProvider( indexName, cfg, buildContext );
indexingParameters = CommonPropertiesParse.extractIndexingPerformanceOptions( cfg );
optimizer = CommonPropertiesParse.getOptimizerStrategy( this, cfg );
backend = createBackend( indexName, cfg, buildContext );
directoryProvider.start( this );
readers = createIndexReader( indexName, cfg, buildContext );
serviceManager = buildContext.getServiceManager();
}
@Override
public Set<Class<?>> getContainedTypes() {
return containedEntityTypes;
}
@Override
public Similarity getSimilarity() {
return similarity;
}
@Override
public void setSimilarity(Similarity newSimilarity) {
this.similarity = newSimilarity;
//TODO fix similarity: it's currently being set multiple times before reaching the final
// configuration, possibly *after* the backend was created, so we have to fix the backend too.
triggerWorkspaceReconfiguration();
if ( writerConfig != null ) {
writerConfig.setSimilarity( similarity );
}
}
@Override
public void performStreamOperation(LuceneWork singleOperation, IndexingMonitor monitor, boolean forceAsync) {
//TODO implement async
backend.applyStreamWork( singleOperation, monitor );
}
@Override
public void performOperations(List<LuceneWork> workList, IndexingMonitor monitor) {
backend.applyWork( workList, monitor );
}
@Override
public String toString() {
return "DirectoryBasedIndexManager [indexName=" + indexName + "]";
}
@Override
public Analyzer getAnalyzer(String name) {
return boundSearchFactory.getAnalyzer( name );
}
@Override
public void setSearchFactory(SearchFactoryImplementor boundSearchFactory) {
this.boundSearchFactory = boundSearchFactory;
triggerWorkspaceReconfiguration();
}
@Override
public void addContainedEntity(Class<?> entity) {
containedEntityTypes.add( entity );
triggerWorkspaceReconfiguration();
}
@Override
public void optimize() {
performStreamOperation( OptimizeLuceneWork.INSTANCE, null, false );
}
//Not exposed on the IndexManager interface
public BackendQueueProcessor getBackendQueueProcessor() {
return backend;
}
//Not exposed on the IndexManager interface
public void setIndexWriterConfig(IndexWriterConfig writerConfig) {
this.writerConfig = writerConfig;
}
//Not exposed on the IndexManager interface
public EntityIndexBinder getIndexBindingForEntity(Class<?> entityType) {
return boundSearchFactory.getIndexBindingForEntity( entityType );
}
//Not exposed on the IndexManager interface
public Lock getDirectoryModificationLock() {
return backend.getExclusiveWriteLock();
}
//Not exposed on the interface
public DirectoryProvider getDirectoryProvider() {
return directoryProvider;
}
//Not exposed on the interface
public OptimizerStrategy getOptimizerStrategy() {
return optimizer;
}
//Not exposed on the interface
public LuceneIndexingParameters getIndexingParameters() {
return indexingParameters;
}
@Override
public LuceneWorkSerializer getSerializer() {
if ( serializer == null ) {
EmptyBuildContext buildContext = new EmptyBuildContext( serviceManager, boundSearchFactory );
serializer = serviceManager.requestService( SerializerService.class, buildContext );
log.indexManagerUsesSerializationService( this.indexName, this.serializer.describeSerializer() );
}
return serializer;
}
private void triggerWorkspaceReconfiguration() {
if ( boundSearchFactory != null ) { //otherwise it's too early
backend.indexMappingChanged();
}
}
/**
* extensions points from {@link #initialize(String, Properties, WorkerBuildContext)}
*/
protected BackendQueueProcessor createBackend(String indexName, Properties cfg, WorkerBuildContext buildContext) {
return BackendFactory.createBackend( this, buildContext, cfg );
}
protected DirectoryBasedReaderProvider createIndexReader(String indexName, Properties cfg, WorkerBuildContext buildContext) {
return CommonPropertiesParse.createDirectoryBasedReaderProvider( this, cfg );
}
protected DirectoryProvider createDirectoryProvider(String indexName, Properties cfg, WorkerBuildContext buildContext) {
return DirectoryProviderFactory.createDirectoryProvider( indexName, cfg, buildContext );
}
}