io.searchbox.client.http.JestHttpClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jest Show documentation
Show all versions of jest Show documentation
ElasticSearch Java REST client - Apache HTTP Client package
package io.searchbox.client.http;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.searchbox.action.Action;
import io.searchbox.client.AbstractJestClient;
import io.searchbox.client.JestResult;
import io.searchbox.client.JestResultHandler;
import io.searchbox.client.JestRetryHandler;
import io.searchbox.client.config.exception.CouldNotConnectException;
import io.searchbox.client.http.apache.HttpDeleteWithEntity;
import io.searchbox.client.http.apache.HttpGetWithEntity;
import org.apache.http.Header;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.ConnectException;
import java.util.Map.Entry;
import java.util.concurrent.Future;
/**
* @author Dogukan Sonmez
* @author cihat keser
*/
public class JestHttpClient extends AbstractJestClient {
private final static Logger log = LoggerFactory.getLogger(JestHttpClient.class);
protected ContentType requestContentType = ContentType.APPLICATION_JSON.withCharset("utf-8");
private CloseableHttpClient httpClient;
private CloseableHttpAsyncClient asyncClient;
private HttpClientContext httpClientContextTemplate;
private JestRetryHandler retryHandler;
/**
* @throws IOException in case of a problem or the connection was aborted during request,
* or in case of a problem while reading the response stream
* @throws CouldNotConnectException if an {@link HttpHostConnectException} is encountered
*/
@Override
public T execute(Action clientRequest) throws IOException {
return execute(clientRequest, null);
}
public T execute(Action clientRequest, RequestConfig requestConfig) throws IOException {
final JestRetryHandler retryHandler = getRetryHandler();
int executionCount = 0;
CloseableHttpResponse response = null;
try {
HttpUriRequest request;
do {
request = prepareRequest(clientRequest, requestConfig);
try {
response = executeRequest(request);
} catch (HttpHostConnectException ex) {
if (!retryHandler.retryRequest(ex, executionCount++, request)) {
throw new CouldNotConnectException(ex.getHost().toURI(), ex);
}
} catch (ConnectException ex) {
if (!retryHandler.retryRequest(ex, executionCount++, request)) {
throw ex;
}
}
} while (response == null);
return deserializeResponse(response, request, clientRequest);
} finally {
if (response != null) {
try {
response.close();
} catch (IOException ex) {
log.error("Exception occurred while closing response stream.", ex);
}
}
}
}
@Override
public void executeAsync(final Action clientRequest, final JestResultHandler super T> resultHandler) throws IOException {
executeAsync(clientRequest, resultHandler, null);
}
public void executeAsync(final Action clientRequest, final JestResultHandler super T> resultHandler, final RequestConfig requestConfig) throws IOException {
synchronized (this) {
if (!asyncClient.isRunning()) {
asyncClient.start();
}
}
HttpUriRequest request = prepareRequest(clientRequest, requestConfig);
executeAsyncRequest(clientRequest, resultHandler, request);
}
@Override
public void shutdownClient() {
try {
close();
} catch (IOException e) {
log.error("Exception occurred while shutting down the sync client.", e);
}
}
@Override
public void close() throws IOException {
super.close();
asyncClient.close();
httpClient.close();
}
protected HttpUriRequest prepareRequest(final Action clientRequest, final RequestConfig requestConfig) throws IOException {
String elasticSearchRestUrl = getRequestURL(getNextServer(), clientRequest.getURI());
HttpUriRequest request = constructHttpMethod(clientRequest.getRestMethodName(), elasticSearchRestUrl, clientRequest.getData(objectMapper), requestConfig);
log.debug("Request method={} url={}", clientRequest.getRestMethodName(), elasticSearchRestUrl);
// add headers added to action
for (Entry header : clientRequest.getHeaders().entrySet()) {
request.addHeader(header.getKey(), header.getValue().toString());
}
return request;
}
protected CloseableHttpResponse executeRequest(HttpUriRequest request) throws IOException {
if (httpClientContextTemplate != null) {
return httpClient.execute(request, createContextInstance());
}
return httpClient.execute(request);
}
protected Future executeAsyncRequest(Action clientRequest, JestResultHandler super T> resultHandler, HttpUriRequest request) {
if (httpClientContextTemplate != null) {
return asyncClient.execute(request, createContextInstance(), new DefaultCallback(clientRequest, request, resultHandler));
}
return asyncClient.execute(request, new DefaultCallback(clientRequest, request, resultHandler));
}
protected HttpClientContext createContextInstance() {
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(httpClientContextTemplate.getCredentialsProvider());
context.setAuthCache(httpClientContextTemplate.getAuthCache());
return context;
}
protected HttpUriRequest constructHttpMethod(String methodName, String url, String payload, RequestConfig requestConfig) {
HttpUriRequest httpUriRequest = null;
if (methodName.equalsIgnoreCase("POST")) {
httpUriRequest = new HttpPost(url);
log.debug("POST method created based on client request");
} else if (methodName.equalsIgnoreCase("PUT")) {
httpUriRequest = new HttpPut(url);
log.debug("PUT method created based on client request");
} else if (methodName.equalsIgnoreCase("DELETE")) {
httpUriRequest = new HttpDeleteWithEntity(url);
log.debug("DELETE method created based on client request");
} else if (methodName.equalsIgnoreCase("GET")) {
httpUriRequest = new HttpGetWithEntity(url);
log.debug("GET method created based on client request");
} else if (methodName.equalsIgnoreCase("HEAD")) {
httpUriRequest = new HttpHead(url);
log.debug("HEAD method created based on client request");
}
if (httpUriRequest instanceof HttpRequestBase && requestConfig != null) {
((HttpRequestBase) httpUriRequest).setConfig(requestConfig);
}
if (httpUriRequest != null && httpUriRequest instanceof HttpEntityEnclosingRequest && payload != null) {
EntityBuilder entityBuilder = EntityBuilder.create()
.setText(payload)
.setContentType(requestContentType);
if (isRequestCompressionEnabled()) {
entityBuilder.gzipCompress();
}
((HttpEntityEnclosingRequest) httpUriRequest).setEntity(entityBuilder.build());
}
return httpUriRequest;
}
private T deserializeResponse(HttpResponse response, final HttpRequest httpRequest, Action clientRequest) throws IOException {
StatusLine statusLine = response.getStatusLine();
try {
return clientRequest.createNewElasticSearchResult(
response.getEntity() == null ? null : EntityUtils.toString(response.getEntity()),
statusLine.getStatusCode(),
statusLine.getReasonPhrase(),
objectMapper
);
} catch (JsonParseException e) {
for (Header header : response.getHeaders("Content-Type")) {
final String mimeType = header.getValue();
if (!mimeType.startsWith("application/json")) {
// probably a proxy that responded in text/html
final String message = "Request " + httpRequest.toString() + " yielded " + mimeType
+ ", should be json: " + statusLine.toString();
throw new IOException(message, e);
}
}
throw e;
}
}
public CloseableHttpClient getHttpClient() {
return httpClient;
}
public void setHttpClient(CloseableHttpClient httpClient) {
this.httpClient = httpClient;
}
public CloseableHttpAsyncClient getAsyncClient() {
return asyncClient;
}
public void setAsyncClient(CloseableHttpAsyncClient asyncClient) {
this.asyncClient = asyncClient;
}
public ObjectMapper getObjectMapper() {
return objectMapper;
}
public void setObjectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
public HttpClientContext getHttpClientContextTemplate() {
return httpClientContextTemplate;
}
public void setHttpClientContextTemplate(HttpClientContext httpClientContext) {
this.httpClientContextTemplate = httpClientContext;
}
public JestRetryHandler getRetryHandler() {
return retryHandler;
}
public JestHttpClient setRetryHandler(JestRetryHandler retryHandler) {
this.retryHandler = retryHandler;
return this;
}
protected class DefaultCallback implements FutureCallback {
private final Action clientRequest;
private final HttpRequest request;
private final JestResultHandler super T> resultHandler;
public DefaultCallback(Action clientRequest, final HttpRequest request, JestResultHandler super T> resultHandler) {
this.clientRequest = clientRequest;
this.request = request;
this.resultHandler = resultHandler;
}
@Override
public void completed(final HttpResponse response) {
T jestResult = null;
try {
jestResult = deserializeResponse(response, request, clientRequest);
} catch (Exception e) {
failed(e);
} catch (Throwable t) {
failed(new Exception("Problem during request processing", t));
}
if (jestResult != null) resultHandler.completed(jestResult);
}
@Override
public void failed(final Exception ex) {
log.error("Exception occurred during async execution.", ex);
if (ex instanceof HttpHostConnectException) {
String host = ((HttpHostConnectException) ex).getHost().toURI();
resultHandler.failed(new CouldNotConnectException(host, ex));
return;
}
resultHandler.failed(ex);
}
@Override
public void cancelled() {
log.warn("Async execution was cancelled; this is not expected to occur under normal operation.");
}
}
}