Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.symphony.bdk.bot.sdk.lib.restclient.RestClientImpl Maven / Gradle / Ivy
package com.symphony.bdk.bot.sdk.lib.restclient;
import io.github.resilience4j.bulkhead.Bulkhead;
import io.github.resilience4j.bulkhead.BulkheadConfig;
import io.github.resilience4j.bulkhead.BulkheadRegistry;
import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import com.symphony.bdk.bot.sdk.lib.restclient.model.RestResponse;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.function.Supplier;
/**
* Spring RestTemplate-based implementation of the {@link RestClient}
*
* @author Marcus Secato
*
*/
public class RestClientImpl implements RestClient {
private static final Logger LOGGER = LoggerFactory.getLogger(RestClientImpl.class);
private RestTemplate restTemplate;
private CircuitBreakerConfig cbConfig;
private CircuitBreakerRegistry cbRegistry;
private BulkheadConfig bhConfig;
private BulkheadRegistry bhRegistry;
public RestClientImpl(
RestTemplate restTemplate, CircuitBreakerConfig cbConfig, BulkheadConfig bhConfig) {
this.restTemplate = restTemplate;
this.cbConfig = cbConfig;
this.bhConfig = bhConfig;
cbRegistry = CircuitBreakerRegistry.of(cbConfig);
bhRegistry = BulkheadRegistry.of(bhConfig);
}
/**
* {@inheritDoc}
*/
@Override
public RestResponse getRequest(String url, Class clazz) {
return doRequest(url, HttpMethod.GET, null, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public RestResponse getRequest(String url,
Map headers, Class clazz) {
return doRequest(url, HttpMethod.GET, headers, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public RestResponse postRequest(String url, U body,
Class clazz) {
return doRequestWithBody(url, HttpMethod.POST, null, body, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public RestResponse postRequest(String url, U body,
Map headers, Class clazz) {
return doRequestWithBody(url, HttpMethod.POST, headers, body, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public RestResponse putRequest(String url, U body,
Class clazz) {
return doRequestWithBody(url, HttpMethod.PUT, null, body, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public RestResponse putRequest(String url, U body,
Map headers, Class clazz) {
return doRequestWithBody(url, HttpMethod.PUT, headers, body, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public RestResponse deleteRequest(String url, Class clazz) {
return doRequest(url, HttpMethod.DELETE, null, clazz);
}
/**
* {@inheritDoc}
*/
@Override
public RestResponse deleteRequest(String url,
Map headers, Class clazz) {
return doRequest(url, HttpMethod.DELETE, headers, clazz);
}
private RestResponse doRequest(String url, HttpMethod httpMethod,
Map headers, Class clazz) {
HttpEntity> httpEntity = new HttpEntity<>(convertHeaders(headers));
return applyResourceControl(url, httpMethod, httpEntity, clazz);
}
private RestResponse doRequestWithBody(String url,
HttpMethod httpMethod, Map headers, U body, Class clazz) {
HttpEntity> httpEntity = new HttpEntity<>(body, convertHeaders(headers));
return applyResourceControl(url, httpMethod, httpEntity, clazz);
}
/**
* Applies circuit-breaker and bulkhead controls to improve resources usage
* when communicating with external systems.
*/
private RestResponse applyResourceControl(String url,
HttpMethod httpMethod, HttpEntity> httpEntity, Class clazz) {
String registryKey = getBaseUrl(url);
CircuitBreaker cb = cbRegistry.circuitBreaker(registryKey, cbConfig);
Supplier> cbSupplier = CircuitBreaker.decorateSupplier(cb,
() -> internalDoRequest(url, httpMethod, httpEntity, clazz));
Bulkhead bh = bhRegistry.bulkhead(registryKey, bhConfig);
Supplier> bhSupplier = Bulkhead.decorateSupplier(
bh, cbSupplier);
try {
return bhSupplier.get();
} catch (CallNotPermittedException cnpe) {
LOGGER.warn("Circuit breaker is now OPEN. Rejecting request {}", url);
throw new RestClientConnectionException();
}
}
private RestResponse internalDoRequest(String url,
HttpMethod httpMethod, HttpEntity> httpEntity, Class clazz) {
LOGGER.debug("Performing request {} {}", httpMethod, url);
RestResponse response = null;
try {
ResponseEntity re = restTemplate.exchange(
url, httpMethod, httpEntity, clazz);
T body = re.hasBody() ? re.getBody() : null;
response = new RestResponse<>(body,
re.getHeaders().toSingleValueMap(), re.getStatusCodeValue());
} catch (HttpClientErrorException | HttpServerErrorException reqEx) {
LOGGER.debug("Unsuccessful response executing request {} {}\n",
httpMethod, url, reqEx);
response = new RestResponse<>(
reqEx.getResponseHeaders().toSingleValueMap(),
reqEx.getRawStatusCode());
} catch (RestClientException rce) {
LOGGER.error("Unexpected error executing request {} {}\n{}",
httpMethod, url, rce);
throw new RestClientConnectionException();
}
return response;
}
private MultiValueMap convertHeaders(
Map headers) {
if (headers != null) {
MultiValueMap resttemplateHeaders =
new LinkedMultiValueMap<>();
headers.entrySet().stream()
.forEach(e -> resttemplateHeaders.add(e.getKey(), e.getValue()));
return resttemplateHeaders;
}
return null;
}
private String getBaseUrl(String url) {
try {
URI uri = new URI(url);
return uri.getHost();
} catch (URISyntaxException use) {
LOGGER.debug("Could not parse URL: {}", url);
return url;
}
}
}