
com.github.davidmoten.odata.client.internal.ApacheHttpClientHttpService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of odata-client-runtime Show documentation
Show all versions of odata-client-runtime Show documentation
OData client runtime for use with generated code
The newest version!
package com.github.davidmoten.odata.client.internal;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPatch;
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.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.davidmoten.guavamini.Preconditions;
import com.github.davidmoten.odata.client.ClientException;
import com.github.davidmoten.odata.client.HttpMethod;
import com.github.davidmoten.odata.client.HttpRequestOptions;
import com.github.davidmoten.odata.client.HttpResponse;
import com.github.davidmoten.odata.client.HttpService;
import com.github.davidmoten.odata.client.Path;
import com.github.davidmoten.odata.client.RequestHeader;
public class ApacheHttpClientHttpService implements HttpService {
private static final Logger log = LoggerFactory.getLogger(ApacheHttpClientHttpService.class);
private final Path basePath;
private final CloseableHttpClient client;
private final BiFunction, List> requestHeadersModifier;
public ApacheHttpClientHttpService(Path basePath, Supplier clientSupplier,
BiFunction, List> requestHeadersModifier) {
this.basePath = basePath;
this.client = clientSupplier.get();
this.requestHeadersModifier = requestHeadersModifier;
}
public ApacheHttpClientHttpService(Path basePath) {
this(basePath, () -> HttpClientBuilder.create().useSystemProperties().build(),
(url, m) -> m);
}
@Override
public HttpResponse submit(HttpMethod method, String url, List requestHeaders,
InputStream content, int length, HttpRequestOptions options) {
return getResponse(requestHeaders, toRequestBase(method, url), content, length, options);
}
@Override
public Path getBasePath() {
return basePath;
}
private static URL toUrl(HttpRequestBase request) {
try {
return request.getURI().toURL();
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
private HttpResponse getResponse(List requestHeaders, HttpRequestBase request,
InputStream content, int length, HttpRequestOptions options) {
Preconditions.checkNotNull(options);
log.debug("{} from url {}", request.getMethod(), request.getURI());
log.debug("requestHeaders={}", requestHeaders);
for (RequestHeader header : requestHeadersModifier.apply(toUrl(request), requestHeaders)) {
request.addHeader(header.name(), header.value());
}
try {
if (content != null && request instanceof HttpEntityEnclosingRequest) {
((HttpEntityEnclosingRequest) request)
.setEntity(new InputStreamEntity(content, length));
log.debug("content={}", content);
}
RequestConfig config = com.github.davidmoten.odata.client.Util.nvl(request.getConfig(),
RequestConfig.DEFAULT);
Builder builder = RequestConfig //
.copy(config);
options.requestConnectTimeoutMs()
.ifPresent(x -> builder.setConnectTimeout(x.intValue()));
options.requestReadTimeoutMs().ifPresent(x -> builder.setSocketTimeout(x.intValue()));
config = builder.build();
request.setConfig(config);
log.debug("executing request");
try (CloseableHttpResponse response = client.execute(request)) {
int statusCode = response.getStatusLine().getStatusCode();
log.debug("executed request, code={}", statusCode);
HttpEntity entity = response.getEntity();
final byte[] bytes;
if (entity == null) {
bytes = null;
} else {
bytes = Util.read(entity.getContent());
}
if (log.isDebugEnabled()) {
log.debug("response text=\n{}",
bytes == null ? "null" : new String(bytes, StandardCharsets.UTF_8));
}
return new HttpResponse(statusCode, bytes);
}
} catch (IOException e) {
throw new ClientException(e);
}
}
@Override
public InputStream getStream(HttpMethod method, String url, List requestHeaders,
HttpRequestOptions options) {
HttpRequestBase b = toRequestBase(method, url);
return getStream(requestHeaders, b, null, 0, options);
}
private static HttpRequestBase toRequestBase(HttpMethod method, String url) {
if (method == HttpMethod.GET) {
return new HttpGet(url);
} else if (method == HttpMethod.DELETE) {
return new HttpDelete(url);
} else if (method == HttpMethod.PATCH) {
return new HttpPatch(url);
} else if (method == HttpMethod.PUT) {
return new HttpPut(url);
} else if (method == HttpMethod.POST) {
return new HttpPost(url);
} else {
throw new UnsupportedOperationException(method.toString() + " not recognized");
}
}
public InputStream getStream(List requestHeaders, HttpRequestBase request,
InputStream content, int length, HttpRequestOptions options) {
Preconditions.checkNotNull(options);
log.debug("{} from url {}", request.getMethod(), request.getURI());
log.debug("requestHeaders={}", requestHeaders);
boolean contentLengthSet = false;
for (RequestHeader header : requestHeadersModifier.apply(toUrl(request), requestHeaders)) {
request.addHeader(header.name(), header.value());
if ("Content-Length".equals(header.name())) {
contentLengthSet = true;
}
}
if (content != null && !contentLengthSet) {
request.addHeader("Content-Length", Integer.toString(length));
}
CloseableHttpResponse response = null;
try {
if (content != null && request instanceof HttpEntityEnclosingRequest) {
((HttpEntityEnclosingRequest) request)
.setEntity(new InputStreamEntity(content, length));
log.debug("content={}", content);
}
RequestConfig config = com.github.davidmoten.odata.client.Util.nvl(request.getConfig(),
RequestConfig.DEFAULT);
Builder builder = RequestConfig //
.copy(config);
options.requestConnectTimeoutMs()
.ifPresent(x -> builder.setConnectTimeout(x.intValue()));
options.requestReadTimeoutMs().ifPresent(x -> builder.setSocketTimeout(x.intValue()));
config = builder.build();
request.setConfig(config);
log.debug("executing request");
response = client.execute(request);
int statusCode = response.getStatusLine().getStatusCode();
log.debug("executed request, code={}", statusCode);
InputStream is = response.getEntity().getContent();
// ensure response is closed when input stream is closed
InputStream in = new InputStreamWithCloseable(is, response);
if (!isOk(statusCode)) {
try {
String msg = Util.readString(in, StandardCharsets.UTF_8);
throw new ClientException(statusCode,
"getStream returned HTTP " + statusCode + "\n" //
+ "url=" + request.getURI() + "\n" //
+ "headers=" + requestHeaders + "\n" //
+ "response:\n" //
+ msg);
} finally {
in.close();
}
} else {
return in;
}
} catch (IOException e) {
// ensure that response is closed on exception to avoid memory leak
if (response != null) {
try {
response.close();
} catch (IOException e1) {
log.warn(e1.getMessage(), e);
}
}
throw new ClientException(e);
}
}
@Override
public void close() throws Exception {
log.info("closing client");
client.close();
log.info("closed client");
}
private static boolean isOk(int statusCode) {
return statusCode >= 200 && statusCode < 300;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy