/*
* This file is part of ReadonlyREST.
*
* ReadonlyREST is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ReadonlyREST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ReadonlyREST. If not, see http://www.gnu.org/licenses/
*/
package org.elasticsearch.plugin.readonlyrest.es;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseListener;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.plugin.readonlyrest.acl.domain.HttpMethod;
import org.elasticsearch.plugin.readonlyrest.httpclient.HttpClient;
import org.elasticsearch.plugin.readonlyrest.httpclient.HttpClientConfig;
import org.elasticsearch.plugin.readonlyrest.httpclient.HttpClientFactory;
import org.elasticsearch.plugin.readonlyrest.httpclient.HttpRequest;
import org.elasticsearch.plugin.readonlyrest.httpclient.HttpResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
public enum ESHttpClientFactory implements HttpClientFactory {
INSTANCE;
@Override
public HttpClient create(HttpClientConfig config) {
return new HttpClient() {
private RestClient underlyingClient = RestClient.builder(new HttpHost(config.getHost(), config.getPort())).build();
@Override
public CompletableFuture<HttpResponse> send(HttpRequest request) {
CompletableFuture<HttpResponse> promise = new CompletableFuture<>();
underlyingClient.performRequestAsync(
httpMethodToString(request.getMethod()),
request.getUrl().getPath(),
request.getQueryParams(),
new CompletableFutureResponseListener(promise),
toHeadersList(request.getHeaders()).toArray(new Header[0])
);
return promise;
}
};
}
private String httpMethodToString(HttpMethod method) {
switch (method) {
case GET:
return "GET";
case POST:
return "POST";
case PUT:
return "PUT";
case DELETE:
return "DELETE";
case OPTIONS:
return "OPTIONS";
case HEAD:
return "HEAD";
default:
throw new IllegalArgumentException();
}
}
private List<Header> toHeadersList(Map<String, String> headersMap) {
return headersMap.entrySet().stream()
.map(entity -> new BasicHeader(entity.getKey(), entity.getValue()))
.collect(Collectors.toList());
}
public static class CompletableFutureResponseListener implements ResponseListener {
private final CompletableFuture<HttpResponse> promise;
CompletableFutureResponseListener(CompletableFuture<HttpResponse> promise) {
this.promise = promise;
}
@Override
public void onSuccess(Response response) {
try {
promise.complete(from(response));
} catch (IOException e) {
promise.completeExceptionally(e);
}
}
@Override
public void onFailure(Exception exception) {
promise.completeExceptionally(exception);
}
private HttpResponse from(Response response) throws IOException {
return new HttpResponse(response.getStatusLine().getStatusCode(), () -> {
try {
return response.getEntity().getContent();
} catch (IOException e) {
throw new RuntimeException("Cannot read content");
}
});
}
}
}