DATAES-751 - Introduce ClientCallback for the rest client.

Original PR: #401
This commit is contained in:
Peter-Josef Meisch 2020-03-11 12:34:56 +01:00 committed by GitHub
parent ab0c6a8f66
commit 0b0c8027a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 232 additions and 204 deletions

View File

@ -25,7 +25,9 @@ import org.springframework.lang.Nullable;
* @author Rizwan Idrees
* @author Mohsin Husen
* @author Peter-Josef Meisch
* @deprecated since 4.0, use {@link org.springframework.dao.UncategorizedDataAccessException}
*/
@Deprecated
public class ElasticsearchException extends RuntimeException {
@Nullable private Map<String, String> failedDocuments;

View File

@ -0,0 +1,28 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch;
import org.springframework.dao.UncategorizedDataAccessException;
/**
* @author Peter-Josef Meisch
* @since 4.0
*/
public class UncategorizedElasticsearchException extends UncategorizedDataAccessException {
public UncategorizedElasticsearchException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -33,14 +33,12 @@ import org.elasticsearch.client.Request;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.PutMappingRequest;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.springframework.data.elasticsearch.ElasticsearchException;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
import org.springframework.data.elasticsearch.core.client.support.AliasData;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.AliasQuery;
@ -60,29 +58,22 @@ import com.fasterxml.jackson.databind.ObjectMapper;
*/
class DefaultIndexOperations extends AbstractDefaultIndexOperations implements IndexOperations {
private RestHighLevelClient client;
private ElasticsearchRestTemplate restTemplate;
public DefaultIndexOperations(RestHighLevelClient client, ElasticsearchConverter elasticsearchConverter,
Class<?> boundClass) {
super(elasticsearchConverter, boundClass);
this.client = client;
public DefaultIndexOperations(ElasticsearchRestTemplate restTemplate, Class<?> boundClass) {
super(restTemplate.getElasticsearchConverter(), boundClass);
this.restTemplate = restTemplate;
}
public DefaultIndexOperations(RestHighLevelClient client, ElasticsearchConverter elasticsearchConverter,
IndexCoordinates boundIndex) {
super(elasticsearchConverter, boundIndex);
this.client = client;
public DefaultIndexOperations(ElasticsearchRestTemplate restTemplate, IndexCoordinates boundIndex) {
super(restTemplate.getElasticsearchConverter(), boundIndex);
this.restTemplate = restTemplate;
}
@Override
protected boolean doCreate(String indexName, @Nullable Document settings) {
CreateIndexRequest request = requestFactory.createIndexRequest(indexName, settings);
try {
return client.indices().create(request, RequestOptions.DEFAULT).isAcknowledged();
} catch (IOException e) {
throw new ElasticsearchException(
"Error for creating index: " + indexName + ", client: " + client.getLowLevelClient().getNodes(), e);
}
return restTemplate.execute(client -> client.indices().create(request, RequestOptions.DEFAULT).isAcknowledged());
}
@Override
@ -92,11 +83,7 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
if (doExists(indexName)) {
DeleteIndexRequest request = new DeleteIndexRequest(indexName);
try {
return client.indices().delete(request, RequestOptions.DEFAULT).isAcknowledged();
} catch (IOException e) {
throw new ElasticsearchException("Error while deleting index request: " + request.toString(), e);
}
return restTemplate.execute(client -> client.indices().delete(request, RequestOptions.DEFAULT).isAcknowledged());
}
return false;
}
@ -104,11 +91,7 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
@Override
protected boolean doExists(String indexName) {
GetIndexRequest request = new GetIndexRequest(indexName);
try {
return client.indices().exists(request, RequestOptions.DEFAULT);
} catch (IOException e) {
throw new ElasticsearchException("Error while for indexExists request: " + request.toString(), e);
}
return restTemplate.execute(client -> client.indices().exists(request, RequestOptions.DEFAULT));
}
@Override
@ -117,11 +100,8 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
Assert.notNull(index, "No index defined for putMapping()");
PutMappingRequest request = requestFactory.putMappingRequest(index, mapping);
try {
return client.indices().putMapping(request, RequestOptions.DEFAULT).isAcknowledged();
} catch (IOException e) {
throw new ElasticsearchException("Failed to put mapping for " + index.getIndexName(), e);
}
return restTemplate
.execute(client -> client.indices().putMapping(request, RequestOptions.DEFAULT).isAcknowledged());
}
@Override
@ -129,24 +109,19 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
Assert.notNull(index, "No index defined for getMapping()");
RestClient restClient = client.getLowLevelClient();
try {
return restTemplate.execute(client -> {
RestClient restClient = client.getLowLevelClient();
Request request = new Request("GET", '/' + index.getIndexName() + "/_mapping");
Response response = restClient.performRequest(request);
return convertMappingResponse(EntityUtils.toString(response.getEntity()));
} catch (Exception e) {
throw new ElasticsearchException("Error while getting mapping for indexName : " + index.getIndexName(), e);
}
});
}
@Override
protected boolean doAddAlias(AliasQuery query, IndexCoordinates index) {
IndicesAliasesRequest request = requestFactory.indicesAddAliasesRequest(query, index);
try {
return client.indices().updateAliases(request, RequestOptions.DEFAULT).isAcknowledged();
} catch (IOException e) {
throw new ElasticsearchException("failed to update aliases with request: " + request, e);
}
return restTemplate
.execute(client -> client.indices().updateAliases(request, RequestOptions.DEFAULT).isAcknowledged());
}
@Override
@ -156,29 +131,23 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
Assert.notNull(query.getAliasName(), "No alias defined");
IndicesAliasesRequest indicesAliasesRequest = requestFactory.indicesRemoveAliasesRequest(query, index);
try {
return client.indices().updateAliases(indicesAliasesRequest, RequestOptions.DEFAULT).isAcknowledged();
} catch (IOException e) {
throw new ElasticsearchException(
"failed to update aliases with indicesRemoveAliasesRequest: " + indicesAliasesRequest, e);
}
return restTemplate.execute(
client -> client.indices().updateAliases(indicesAliasesRequest, RequestOptions.DEFAULT).isAcknowledged());
}
@Override
protected List<AliasMetaData> doQueryForAlias(String indexName) {
List<AliasMetaData> aliases = null;
RestClient restClient = client.getLowLevelClient();
Response response;
String aliasResponse;
return restTemplate.execute(client -> {
RestClient restClient = client.getLowLevelClient();
Response response;
String aliasResponse;
try {
response = restClient.performRequest(new Request("GET", '/' + indexName + "/_alias/*"));
aliasResponse = EntityUtils.toString(response.getEntity());
} catch (Exception e) {
throw new ElasticsearchException("Error while getting mapping for indexName : " + indexName, e);
}
return convertAliasResponse(aliasResponse);
return convertAliasResponse(aliasResponse);
});
}
@Override
@ -190,14 +159,11 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
.indices(indexName) //
.includeDefaults(includeDefaults);
try {
GetSettingsResponse response = client.indices() //
.getSettings(request, RequestOptions.DEFAULT);
//
GetSettingsResponse response = restTemplate.execute(client -> client.indices() //
.getSettings(request, RequestOptions.DEFAULT));
return convertSettingsResponseToMap(response, indexName);
} catch (IOException e) {
throw new ElasticsearchException("failed to get settings for index: " + indexName, e);
}
return convertSettingsResponseToMap(response, indexName);
}
@Override
@ -205,11 +171,8 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
Assert.notNull(index, "No index defined for refresh()");
try {
client.indices().refresh(refreshRequest(index.getIndexNames()), RequestOptions.DEFAULT);
} catch (IOException e) {
throw new ElasticsearchException("failed to refresh index: " + index, e);
}
restTemplate
.execute(client -> client.indices().refresh(refreshRequest(index.getIndexNames()), RequestOptions.DEFAULT));
}
// region Helper methods
@ -225,7 +188,7 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
return result;
} catch (IOException e) {
throw new ElasticsearchException("Could not map alias response : " + mappingResponse, e);
throw new UncategorizedElasticsearchException("Could not map alias response : " + mappingResponse, e);
}
}
@ -261,7 +224,7 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
}
return aliasMetaDataList;
} catch (IOException e) {
throw new ElasticsearchException("Could not map alias response : " + aliasResponse, e);
throw new UncategorizedElasticsearchException("Could not map alias response : " + aliasResponse, e);
}
}
// endregion

View File

@ -16,21 +16,25 @@
package org.springframework.data.elasticsearch.core;
import java.net.ConnectException;
import java.io.IOException;
import java.util.List;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.common.ValidationException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.elasticsearch.NoSuchIndexException;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* @author Christoph Strobl
* @author Peter-Josef Meisch
* @since 3.2
*/
public class ElasticsearchExceptionTranslator implements PersistenceExceptionTranslator {
@ -46,9 +50,15 @@ public class ElasticsearchExceptionTranslator implements PersistenceExceptionTra
return new NoSuchIndexException(ObjectUtils.nullSafeToString(elasticsearchException.getMetadata("es.index")),
ex);
}
return new UncategorizedElasticsearchException(ex.getMessage(), ex);
}
if (ex.getCause() instanceof ConnectException) {
if (ex instanceof ValidationException) {
return new DataIntegrityViolationException(ex.getMessage(), ex);
}
Throwable cause = ex.getCause();
if (cause instanceof IOException) {
return new DataAccessResourceFailureException(ex.getMessage(), ex);
}
@ -60,8 +70,9 @@ public class ElasticsearchExceptionTranslator implements PersistenceExceptionTra
List<String> metadata = ex.getMetadata("es.index_uuid");
if (metadata == null) {
if (ex instanceof ElasticsearchStatusException) {
return StringUtils.hasText(ObjectUtils.nullSafeToString(((ElasticsearchStatusException) ex).getIndex()));
return StringUtils.hasText(ObjectUtils.nullSafeToString(ex.getIndex()));
}
return false;
}
return !CollectionUtils.contains(metadata.iterator(), "_na_");
}

View File

@ -17,7 +17,6 @@ package org.springframework.data.elasticsearch.core;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
@ -40,7 +39,6 @@ import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.ElasticsearchException;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.document.DocumentAdapters;
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
@ -90,25 +88,29 @@ import org.springframework.util.Assert;
public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
private RestHighLevelClient client;
private ElasticsearchExceptionTranslator exceptionTranslator;
// region Initialization
public ElasticsearchRestTemplate(RestHighLevelClient client) {
this.client = client;
initialize(client, createElasticsearchConverter());
}
public ElasticsearchRestTemplate(RestHighLevelClient client, ElasticsearchConverter elasticsearchConverter) {
this.client = client;
initialize(client, elasticsearchConverter);
}
private void initialize(RestHighLevelClient client, ElasticsearchConverter elasticsearchConverter) {
Assert.notNull(client, "Client must not be null!");
this.client = client;
this.exceptionTranslator = new ElasticsearchExceptionTranslator();
initialize(createElasticsearchConverter());
}
public ElasticsearchRestTemplate(RestHighLevelClient client, ElasticsearchConverter elasticsearchConverter) {
Assert.notNull(client, "Client must not be null!");
this.client = client;
this.exceptionTranslator = new ElasticsearchExceptionTranslator();
initialize(elasticsearchConverter);
}
// endregion
// region IndexOperations
@ -117,7 +119,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
Assert.notNull(clazz, "clazz must not be null");
return new DefaultIndexOperations(client, elasticsearchConverter, clazz);
return new DefaultIndexOperations(this, clazz);
}
@Override
@ -125,7 +127,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
Assert.notNull(index, "index must not be null");
return new DefaultIndexOperations(client, elasticsearchConverter, index);
return new DefaultIndexOperations(this, index);
}
// endregion
@ -133,29 +135,21 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
@Override
public String index(IndexQuery query, IndexCoordinates index) {
IndexRequest request = requestFactory.indexRequest(query, index);
try {
String documentId = client.index(request, RequestOptions.DEFAULT).getId();
String documentId = execute(client -> client.index(request, RequestOptions.DEFAULT).getId());
// We should call this because we are not going through a mapper.
if (query.getObject() != null) {
setPersistentEntityId(query.getObject(), documentId);
}
return documentId;
} catch (IOException e) {
throw new ElasticsearchException("Error while index for request: " + request.toString(), e);
// We should call this because we are not going through a mapper.
if (query.getObject() != null) {
setPersistentEntityId(query.getObject(), documentId);
}
return documentId;
}
@Override
@Nullable
public <T> T get(String id, Class<T> clazz, IndexCoordinates index) {
GetRequest request = requestFactory.getRequest(id, index);
try {
GetResponse response = client.get(request, RequestOptions.DEFAULT);
return elasticsearchConverter.mapDocument(DocumentAdapters.from(response), clazz);
} catch (IOException e) {
throw new ElasticsearchException("Error while getting for request: " + request.toString(), e);
}
GetResponse response = execute(client -> client.get(request, RequestOptions.DEFAULT));
return elasticsearchConverter.mapDocument(DocumentAdapters.from(response), clazz);
}
@Override
@ -165,22 +159,14 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
Assert.notEmpty(query.getIds(), "No Id define for Query");
MultiGetRequest request = requestFactory.multiGetRequest(query, index);
try {
MultiGetResponse result = client.mget(request, RequestOptions.DEFAULT);
return elasticsearchConverter.mapDocuments(DocumentAdapters.from(result), clazz);
} catch (IOException e) {
throw new ElasticsearchException("Error while multiget for request: " + request.toString(), e);
}
MultiGetResponse result = execute(client -> client.mget(request, RequestOptions.DEFAULT));
return elasticsearchConverter.mapDocuments(DocumentAdapters.from(result), clazz);
}
@Override
protected boolean doExists(String id, IndexCoordinates index) {
GetRequest request = requestFactory.getRequest(id, index);
try {
return client.get(request, RequestOptions.DEFAULT).isExists();
} catch (IOException e) {
throw new ElasticsearchException("Error while getting for request: " + request.toString(), e);
}
return execute(client -> client.get(request, RequestOptions.DEFAULT).isExists());
}
@Override
@ -208,53 +194,33 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
Assert.notNull(index, "index must not be null");
DeleteRequest request = new DeleteRequest(index.getIndexName(), elasticsearchConverter.convertId(id));
try {
return client.delete(request, RequestOptions.DEFAULT).getId();
} catch (IOException e) {
throw new ElasticsearchException("Error while deleting item request: " + request.toString(), e);
}
return execute(client -> client.delete(request, RequestOptions.DEFAULT).getId());
}
@Override
public void delete(Query query, Class<?> clazz, IndexCoordinates index) {
DeleteByQueryRequest deleteByQueryRequest = requestFactory.deleteByQueryRequest(query, clazz, index);
try {
client.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
} catch (IOException e) {
throw new ElasticsearchException("Error for delete request: " + deleteByQueryRequest.toString(), e);
}
execute(client -> client.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT));
}
@Override
@Deprecated
public void delete(DeleteQuery deleteQuery, IndexCoordinates index) {
DeleteByQueryRequest deleteByQueryRequest = requestFactory.deleteByQueryRequest(deleteQuery, index);
try {
client.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
} catch (IOException e) {
throw new ElasticsearchException("Error for delete request: " + deleteByQueryRequest.toString(), e);
}
execute(client -> client.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT));
}
@Override
public UpdateResponse update(UpdateQuery query, IndexCoordinates index) {
UpdateRequest request = requestFactory.updateRequest(query, index);
try {
org.elasticsearch.action.update.UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT);
UpdateResponse.Result result = UpdateResponse.Result.valueOf(updateResponse.getResult().name());
return new UpdateResponse(result);
} catch (IOException e) {
throw new ElasticsearchException("Error while update for request: " + request.toString(), e);
}
UpdateResponse.Result result = UpdateResponse.Result
.valueOf(execute(client -> client.update(request, RequestOptions.DEFAULT)).getResult().name());
return new UpdateResponse(result);
}
private List<String> doBulkOperation(List<?> queries, BulkOptions bulkOptions, IndexCoordinates index) {
BulkRequest bulkRequest = requestFactory.bulkRequest(queries, bulkOptions, index);
try {
return checkForBulkOperationFailure(client.bulk(bulkRequest, RequestOptions.DEFAULT));
} catch (IOException e) {
throw new ElasticsearchException("Error while bulk for request: " + bulkRequest.toString(), e);
}
return checkForBulkOperationFailure(execute(client -> client.bulk(bulkRequest, RequestOptions.DEFAULT)));
}
// endregion
@ -272,22 +238,14 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
searchRequest.source().size(0);
try {
return SearchHitsUtil.getTotalCount(client.search(searchRequest, RequestOptions.DEFAULT).getHits());
} catch (IOException e) {
throw new ElasticsearchException("Error for search request: " + searchRequest.toString(), e);
}
return SearchHitsUtil
.getTotalCount(execute(client -> client.search(searchRequest, RequestOptions.DEFAULT).getHits()));
}
@Override
public <T> SearchHits<T> search(Query query, Class<T> clazz, IndexCoordinates index) {
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
SearchResponse response;
try {
response = client.search(searchRequest, RequestOptions.DEFAULT);
} catch (IOException e) {
throw new ElasticsearchException("Error for search request: " + searchRequest.toString(), e);
}
SearchResponse response = execute(client -> client.search(searchRequest, RequestOptions.DEFAULT));
return elasticsearchConverter.read(clazz, SearchDocumentResponse.from(response));
}
@ -299,13 +257,8 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
searchRequest.scroll(TimeValue.timeValueMillis(scrollTimeInMillis));
try {
SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);
return elasticsearchConverter.mapResults(SearchDocumentResponse.from(result), clazz, null);
} catch (IOException e) {
throw new ElasticsearchException("Error for search request with scroll: " + searchRequest.toString(), e);
}
SearchResponse result = execute(client -> client.search(searchRequest, RequestOptions.DEFAULT));
return elasticsearchConverter.mapResults(SearchDocumentResponse.from(result), clazz, null);
}
@Override
@ -313,12 +266,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
Class<T> clazz) {
SearchScrollRequest request = new SearchScrollRequest(scrollId);
request.scroll(TimeValue.timeValueMillis(scrollTimeInMillis));
SearchResponse response;
try {
response = client.searchScroll(request, RequestOptions.DEFAULT);
} catch (IOException e) {
throw new ElasticsearchException("Error for search request with scroll: " + request.toString(), e);
}
SearchResponse response = execute(client -> client.searchScroll(request, RequestOptions.DEFAULT));
return elasticsearchConverter.mapResults(SearchDocumentResponse.from(response), clazz, Pageable.unpaged());
}
@ -326,11 +274,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
public void searchScrollClear(String scrollId) {
ClearScrollRequest request = new ClearScrollRequest();
request.addScrollId(scrollId);
try {
client.clearScroll(request, RequestOptions.DEFAULT);
} catch (IOException e) {
throw new ElasticsearchException("Error for search request with scroll: " + request.toString(), e);
}
execute(client -> client.clearScroll(request, RequestOptions.DEFAULT));
}
@Override
@ -339,26 +283,66 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate {
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.suggest(suggestion);
searchRequest.source(sourceBuilder);
try {
return client.search(searchRequest, RequestOptions.DEFAULT);
} catch (IOException e) {
throw new ElasticsearchException("Could not execute search request : " + searchRequest.toString(), e);
}
return execute(client -> client.search(searchRequest, RequestOptions.DEFAULT));
}
@Override
protected MultiSearchResponse.Item[] getMultiSearchResult(MultiSearchRequest request) {
MultiSearchResponse response;
try {
response = client.multiSearch(request, RequestOptions.DEFAULT);
} catch (IOException e) {
throw new ElasticsearchException("Error for search request: " + request.toString(), e);
}
MultiSearchResponse response = execute(client -> client.multiSearch(request, RequestOptions.DEFAULT));
MultiSearchResponse.Item[] items = response.getResponses();
Assert.isTrue(items.length == request.requests().size(), "Response should has same length with queries");
return items;
}
// endregion
// region clientcallback
/**
* Callback interface to be used with {@link #execute(ClientCallback)} for operating directly on
* {@link RestHighLevelClient}.
*
* @since 4.0
*/
@FunctionalInterface
interface ClientCallback<T> {
T doWithClient(RestHighLevelClient client) throws IOException;
}
/**
* Execute a callback with the {@link RestHighLevelClient}
*
* @param callback the callback to execute, must not be {@literal null}
* @param <T> the type returned from the callback
* @return the callback result
* @since 4.0
*/
public <T> T execute(ClientCallback<T> callback) {
Assert.notNull(callback, "callback must not be null");
try {
return callback.doWithClient(client);
} catch (IOException | RuntimeException e) {
throw translateException(e);
}
}
/**
* translates an Exception if possible. Exceptions that are no {@link RuntimeException}s are wrapped in a
* RuntimeException
*
* @param exception the Exception to map
* @return the potentially translated RuntimeException.
* @since 4.0
*/
private RuntimeException translateException(Exception exception) {
RuntimeException runtimeException = exception instanceof RuntimeException ? (RuntimeException) exception
: new RuntimeException(exception.getMessage(), exception);
RuntimeException potentiallyTranslatedException = exceptionTranslator
.translateExceptionIfPossible(runtimeException);
return potentiallyTranslatedException != null ? potentiallyTranslatedException : runtimeException;
}
// endregion
}

View File

@ -16,7 +16,6 @@
package org.springframework.data.elasticsearch.core;
import java.util.List;
import java.util.Optional;
import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.bulk.BulkRequestBuilder;

View File

@ -792,15 +792,6 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
return type != null ? mappingContext.getPersistentEntity(type) : null;
}
private Throwable translateException(Throwable throwable) {
RuntimeException exception = throwable instanceof RuntimeException ? (RuntimeException) throwable
: new RuntimeException(throwable.getMessage(), throwable);
RuntimeException potentiallyTranslatedException = exceptionTranslator.translateExceptionIfPossible(exception);
return potentiallyTranslatedException != null ? potentiallyTranslatedException : throwable;
}
/**
* Obtain the {@link ReactiveElasticsearchClient} to operate upon.
*
@ -812,4 +803,22 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
// endregion
/**
* translates an Exception if possible. Exceptions that are no {@link RuntimeException}s are wrapped in a
* RuntimeException
*
* @param throwable the Throwable to map
* @return the potentially translated RuntimeException.
* @since 4.0
*/
private RuntimeException translateException(Throwable throwable) {
RuntimeException runtimeException = throwable instanceof RuntimeException ? (RuntimeException) throwable
: new RuntimeException(throwable.getMessage(), throwable);
RuntimeException potentiallyTranslatedException = exceptionTranslator
.translateExceptionIfPossible(runtimeException);
return potentiallyTranslatedException != null ? potentiallyTranslatedException : runtimeException;
}
}

View File

@ -25,7 +25,6 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.index.query.IdsQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.slf4j.Logger;
@ -93,8 +92,8 @@ public abstract class AbstractElasticsearchRepository<T, ID> implements Elastics
createIndex();
putMapping();
}
} catch (ElasticsearchException exception) {
LOGGER.warn("Cannot create index: {}", exception.getDetailedMessage());
} catch (Exception exception) {
LOGGER.warn("Cannot create index: {}", exception.getMessage());
}
}

View File

@ -24,6 +24,8 @@ import lombok.Data;
import java.lang.Double;
import java.lang.Long;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
@ -34,6 +36,7 @@ import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.Score;
import org.springframework.data.elasticsearch.annotations.ScriptedField;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
@ -56,6 +59,17 @@ public class EnableNestedElasticsearchRepositoriesTests {
static class Config {}
@Autowired(required = false) private SampleRepository nestedRepository;
@Autowired ElasticsearchOperations operations;
@BeforeEach
void setUp() {
operations.indexOps(SampleEntity.class).delete();
}
@AfterEach
void tearDown() {
operations.indexOps(SampleEntity.class).delete();
}
@Test
public void hasNestedRepository() {

View File

@ -22,9 +22,9 @@ import static org.springframework.data.elasticsearch.annotations.FieldType.*;
import lombok.Builder;
import lombok.Data;
import org.elasticsearch.ElasticsearchStatusException;
import org.junit.jupiter.api.Test;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
@ -57,7 +57,8 @@ public class ElasticsearchRestTemplateTests extends ElasticsearchTemplateTests {
org.springframework.data.elasticsearch.core.document.Document document = org.springframework.data.elasticsearch.core.document.Document
.create();
UpdateQuery updateQuery = UpdateQuery.builder(randomNumeric(5)).withDocument(document).build();
assertThatThrownBy(() -> operations.update(updateQuery, index)).isInstanceOf(ElasticsearchStatusException.class);
assertThatThrownBy(() -> operations.update(updateQuery, index))
.isInstanceOf(UncategorizedElasticsearchException.class);
}
@Data

View File

@ -26,13 +26,13 @@ import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import org.elasticsearch.ElasticsearchException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.dao.DataAccessException;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
@ -102,6 +102,10 @@ public class LogEntityTests {
assertThat(entities).isNotNull().hasSize(1);
}
protected Class<? extends Exception> invalidIpExceptionClass() {
return DataAccessException.class;
}
@Test // DATAES-66
public void shouldThrowExceptionWhenInvalidIPGivenForSearchQuery() {
@ -110,7 +114,7 @@ public class LogEntityTests {
assertThatThrownBy(() -> {
SearchHits<LogEntity> entities = operations.search(searchQuery, LogEntity.class, index);
}).isInstanceOf(ElasticsearchException.class);
}).isInstanceOf(invalidIpExceptionClass());
}
@Test // DATAES-66

View File

@ -15,6 +15,8 @@
*/
package org.springframework.data.elasticsearch.core;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchSecurityException;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration;
@ -28,4 +30,9 @@ public class LogEntityTransportTests extends LogEntityTests {
@Configuration
@Import({ ElasticsearchTemplateConfiguration.class })
static class Config {}
@Override
protected Class<? extends Exception> invalidIpExceptionClass() {
return ElasticsearchException.class;
}
}

View File

@ -39,7 +39,6 @@ import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.AfterEach;
@ -52,6 +51,7 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.TestUtils;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.Score;
@ -436,7 +436,7 @@ public class ReactiveElasticsearchTemplateTests {
template.search(queryWithInvalidPreference, SampleEntity.class) //
.as(StepVerifier::create) //
.expectError(ElasticsearchStatusException.class).verify();
.expectError(UncategorizedElasticsearchException.class).verify();
}
@Test // DATAES-504

View File

@ -22,6 +22,7 @@ import lombok.NoArgsConstructor;
import java.util.Optional;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@ -64,6 +65,12 @@ public class ImmutableElasticsearchRepositoryTests {
indexOperations.refresh();
}
@AfterEach
void tearDown() {
IndexOperations indexOperations = operations.indexOps(ImmutableEntity.class);
indexOperations.delete();
}
@Test // DATAES-281
public void shouldSaveAndFindImmutableDocument() {

View File

@ -32,13 +32,13 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.elasticsearch.action.ActionRequestValidationException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
import org.springframework.data.domain.Page;
@ -148,7 +148,7 @@ public class SimpleElasticsearchRepositoryTests {
sampleEntity.setVersion(System.currentTimeMillis());
// when
assertThatThrownBy(() -> repository.save(sampleEntity)).isInstanceOf(ActionRequestValidationException.class);
assertThatThrownBy(() -> repository.save(sampleEntity)).isInstanceOf(DataIntegrityViolationException.class);
}
@Test