/*
* 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.elasticsearch.impl;
import java.io.IOException;
import java.util.Properties;
import org.hibernate.search.elasticsearch.cfg.ElasticsearchEnvironment;
import org.hibernate.search.elasticsearch.client.impl.ElasticsearchClient;
import org.hibernate.search.elasticsearch.client.impl.ElasticsearchClientFactory;
import org.hibernate.search.elasticsearch.client.impl.ElasticsearchClientImplementor;
import org.hibernate.search.elasticsearch.dialect.impl.ElasticsearchDialect;
import org.hibernate.search.elasticsearch.dialect.impl.ElasticsearchDialectFactory;
import org.hibernate.search.elasticsearch.gson.impl.GsonProvider;
import org.hibernate.search.elasticsearch.processor.impl.ElasticsearchWorkProcessor;
import org.hibernate.search.elasticsearch.schema.impl.DefaultElasticsearchSchemaCreator;
import org.hibernate.search.elasticsearch.schema.impl.DefaultElasticsearchSchemaDropper;
import org.hibernate.search.elasticsearch.schema.impl.DefaultElasticsearchSchemaMigrator;
import org.hibernate.search.elasticsearch.schema.impl.ElasticsearchSchemaAccessor;
import org.hibernate.search.elasticsearch.schema.impl.ElasticsearchSchemaCreator;
import org.hibernate.search.elasticsearch.schema.impl.ElasticsearchSchemaDropper;
import org.hibernate.search.elasticsearch.schema.impl.ElasticsearchSchemaMigrator;
import org.hibernate.search.elasticsearch.schema.impl.ElasticsearchSchemaTranslator;
import org.hibernate.search.elasticsearch.schema.impl.ElasticsearchSchemaValidator;
import org.hibernate.search.elasticsearch.work.impl.factory.ElasticsearchWorkFactory;
import org.hibernate.search.engine.nulls.impl.MissingValueStrategy;
import org.hibernate.search.engine.service.spi.ServiceManager;
import org.hibernate.search.engine.service.spi.ServiceReference;
import org.hibernate.search.engine.service.spi.Startable;
import org.hibernate.search.engine.service.spi.Stoppable;
import org.hibernate.search.exception.SearchException;
import org.hibernate.search.spi.BuildContext;
import org.hibernate.search.util.configuration.impl.ConfigurationParseHelper;
/**
* Provides access to the JEST client.
*
* @author Gunnar Morling
* @author Yoann Rodiere
*/
public class DefaultElasticsearchService implements ElasticsearchService, Startable, Stoppable {
/**
* The name of the scope to get client properties from;
* we currently only have a single client for all index managers.
*/
private static final String CLIENT_SCOPE_NAME = "default";
private static final String QUERY_PROPERTIES_PREFIX = "hibernate.search.";
private ElasticsearchQueryOptions queryOptions;
private ElasticsearchClient client;
private GsonProvider gsonProvider;
private ElasticsearchWorkFactory workFactory;
private ElasticsearchWorkProcessor workProcessor;
private ElasticsearchSchemaCreator schemaCreator;
private ElasticsearchSchemaDropper schemaDropper;
private ElasticsearchSchemaMigrator schemaMigrator;
private ElasticsearchSchemaValidator schemaValidator;
private ElasticsearchSchemaTranslator schemaTranslator;
private MissingValueStrategy missingValueStrategy;
@Override
public void start(Properties properties, BuildContext context) {
ServiceManager serviceManager = context.getServiceManager();
this.queryOptions = createQueryOptions( properties );
ElasticsearchClientImplementor clientImplementor;
try ( ServiceReference<ElasticsearchClientFactory> clientFactory =
serviceManager.requestReference( ElasticsearchClientFactory.class ) ) {
clientImplementor = clientFactory.get().create( CLIENT_SCOPE_NAME, properties );
}
try ( ServiceReference<ElasticsearchDialectFactory> dialectFactory =
serviceManager.requestReference( ElasticsearchDialectFactory.class ) ) {
ElasticsearchDialect dialect = dialectFactory.get().createDialect( clientImplementor, properties );
this.gsonProvider = dialect.createGsonProvider();
clientImplementor.init( gsonProvider );
this.client = clientImplementor;
this.workFactory = dialect.createWorkFactory( gsonProvider );
this.workProcessor = new ElasticsearchWorkProcessor( context, client, gsonProvider, workFactory );
ElasticsearchSchemaAccessor schemaAccessor = new ElasticsearchSchemaAccessor( workFactory, workProcessor );
this.schemaValidator = dialect.createSchemaValidator( schemaAccessor );
this.schemaTranslator = dialect.createSchemaTranslator();
this.schemaCreator = new DefaultElasticsearchSchemaCreator( schemaAccessor );
this.schemaDropper = new DefaultElasticsearchSchemaDropper( schemaAccessor );
this.schemaMigrator = new DefaultElasticsearchSchemaMigrator( schemaAccessor, schemaValidator );
this.missingValueStrategy = dialect.createMissingValueStrategy();
}
}
@Override
public void stop() {
try ( ElasticsearchClient client = this.client;
ElasticsearchWorkProcessor workProcessor = this.workProcessor; ) {
/*
* Nothing to do: we simply take advantage of Java's auto-closing,
* which adds suppressed exceptions as needed and always tries
* to close every resource.
*/
}
catch (IOException | RuntimeException e) {
throw new SearchException( "Failed to shut down the Elasticsearch service", e );
}
this.client = null;
}
@Override
public GsonProvider getGsonProvider() {
return gsonProvider;
}
@Override
public ElasticsearchWorkFactory getWorkFactory() {
return workFactory;
}
@Override
public ElasticsearchWorkProcessor getWorkProcessor() {
return workProcessor;
}
@Override
public ElasticsearchSchemaCreator getSchemaCreator() {
return schemaCreator;
}
@Override
public ElasticsearchSchemaDropper getSchemaDropper() {
return schemaDropper;
}
@Override
public ElasticsearchSchemaMigrator getSchemaMigrator() {
return schemaMigrator;
}
@Override
public ElasticsearchSchemaValidator getSchemaValidator() {
return schemaValidator;
}
@Override
public ElasticsearchSchemaTranslator getSchemaTranslator() {
return schemaTranslator;
}
@Override
public MissingValueStrategy getMissingValueStrategy() {
return missingValueStrategy;
}
@Override
public ElasticsearchQueryOptions getQueryOptions() {
return queryOptions;
}
private ElasticsearchQueryOptions createQueryOptions(Properties properties) {
String scrollTimeout = ConfigurationParseHelper.getIntValue(
properties,
QUERY_PROPERTIES_PREFIX + ElasticsearchEnvironment.SCROLL_TIMEOUT,
ElasticsearchEnvironment.Defaults.SCROLL_TIMEOUT
) + "s";
int scrollFetchSize = ConfigurationParseHelper.getIntValue(
properties,
QUERY_PROPERTIES_PREFIX + ElasticsearchEnvironment.SCROLL_FETCH_SIZE,
ElasticsearchEnvironment.Defaults.SCROLL_FETCH_SIZE
);
int scrollBacktrackingWindowSize = ConfigurationParseHelper.getIntValue(
properties,
QUERY_PROPERTIES_PREFIX + ElasticsearchEnvironment.SCROLL_BACKTRACKING_WINDOW_SIZE,
ElasticsearchEnvironment.Defaults.SCROLL_BACKTRACKING_WINDOW_SIZE
);
return new ElasticsearchQueryOptionsImpl( scrollTimeout, scrollFetchSize, scrollBacktrackingWindowSize );
}
private static class ElasticsearchQueryOptionsImpl implements ElasticsearchQueryOptions {
private final String scrollTimeout;
private final int scrollFetchSize;
private final int scrollBacktrackingWindowSize;
public ElasticsearchQueryOptionsImpl(String scrollTimeout, int scrollFetchSize, int scrollBacktrackingWindowSize) {
super();
this.scrollTimeout = scrollTimeout;
this.scrollFetchSize = scrollFetchSize;
this.scrollBacktrackingWindowSize = scrollBacktrackingWindowSize;
}
@Override
public String getScrollTimeout() {
return scrollTimeout;
}
@Override
public int getScrollFetchSize() {
return scrollFetchSize;
}
@Override
public int getScrollBacktrackingWindowSize() {
return scrollBacktrackingWindowSize;
}
}
}