/* * 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.work.impl; import java.io.IOException; import java.util.stream.Stream; import org.elasticsearch.client.Response; import org.hibernate.search.backend.LuceneWork; import org.hibernate.search.elasticsearch.client.impl.ElasticsearchRequest; import org.hibernate.search.elasticsearch.client.impl.URLEncodedString; import org.hibernate.search.elasticsearch.gson.impl.GsonProvider; import org.hibernate.search.elasticsearch.logging.impl.Log; import org.hibernate.search.elasticsearch.util.impl.ElasticsearchClientUtils; import org.hibernate.search.exception.SearchException; import org.hibernate.search.util.logging.impl.LoggerFactory; import com.google.gson.JsonObject; /** * @author Gunnar Morling * @author Yoann Rodiere */ public abstract class SimpleElasticsearchWork<R> implements ElasticsearchWork<R> { private static final Log LOG = LoggerFactory.make( Log.class ); protected final ElasticsearchRequest request; private final LuceneWork luceneWork; protected final URLEncodedString dirtiedIndexName; protected final ElasticsearchRequestSuccessAssessor resultAssessor; protected final boolean markIndexDirty; protected SimpleElasticsearchWork(Builder<?> builder) { this.request = builder.buildRequest(); this.luceneWork = builder.luceneWork; this.dirtiedIndexName = builder.dirtiedIndexName; this.resultAssessor = builder.resultAssessor; this.markIndexDirty = builder.markIndexDirty; } @Override public String toString() { return new StringBuilder() .append( getClass().getSimpleName() ) .append( "[" ) .append( "path = " ).append( request.getPath() ) .append( ", dirtiedIndexName = " ).append( dirtiedIndexName ) .append( "]" ) .toString(); } @Override public final R execute(ElasticsearchWorkExecutionContext executionContext) { GsonProvider gsonProvider = executionContext.getGsonProvider(); Response response = null; JsonObject parsedResponseBody = null; R result; try { beforeExecute( executionContext, request ); response = executionContext.getClient().execute( request ); parsedResponseBody = ElasticsearchClientUtils.parseJsonResponse( gsonProvider, response ); resultAssessor.checkSuccess( executionContext, request, response, parsedResponseBody ); result = generateResult( executionContext, response, parsedResponseBody ); } catch (SearchException e) { throw e; // Do not add context for those: we expect SearchExceptions to be self-explanatory } catch (IOException | RuntimeException e) { throw LOG.elasticsearchRequestFailed( ElasticsearchClientUtils.formatRequest( gsonProvider, request ), ElasticsearchClientUtils.formatResponse( gsonProvider, response, parsedResponseBody ), e ); } if ( markIndexDirty ) { executionContext.setIndexDirty( dirtiedIndexName ); } afterSuccess( executionContext ); return result; } protected void beforeExecute(ElasticsearchWorkExecutionContext executionContext, ElasticsearchRequest request) { // Do nothing by default } protected void afterSuccess(ElasticsearchWorkExecutionContext executionContext) { // Do nothing by default } protected abstract R generateResult(ElasticsearchWorkExecutionContext context, Response response, JsonObject parsedResponseBody); @Override public void aggregate(ElasticsearchWorkAggregator aggregator) { // May be overridden by subclasses aggregator.addNonBulkable( this ); } @Override public Stream<LuceneWork> getLuceneWorks() { if ( luceneWork != null ) { return Stream.of( luceneWork ); } else { return Stream.empty(); } } @SuppressWarnings("unchecked") // By contract, subclasses must implement B protected abstract static class Builder<B> { protected final URLEncodedString dirtiedIndexName; protected ElasticsearchRequestSuccessAssessor resultAssessor; protected LuceneWork luceneWork; protected boolean markIndexDirty; public Builder(URLEncodedString dirtiedIndexName, ElasticsearchRequestSuccessAssessor resultAssessor) { this.dirtiedIndexName = dirtiedIndexName; this.resultAssessor = resultAssessor; } public B luceneWork(LuceneWork luceneWork) { this.luceneWork = luceneWork; return (B) this; } public B markIndexDirty(boolean markIndexDirty) { this.markIndexDirty = markIndexDirty; return (B) this; } protected abstract ElasticsearchRequest buildRequest(); public abstract ElasticsearchWork<?> build(); } }