Java 8 RestService: Efficient way to set Response Timeout in Spring bean - java

I'm writing a custom RestService(wrapper of Apache Http Client 4.5.10) and RestServiceAsync(wrapper of Apache httpasyncclient 4.1.4) in Spring MVC monolithic application.
Below is my IRestService
public interface IRestService {
public <T> T request(HttpUriRequest request, final ResponseParser<T> responseParser);
public <T> Optional<T> request(final HttpMethod method);
public <T> T call(HttpUriRequest request, ResponseHandler<T> responseHandler);
default <T> Optional<T> get() {
return request(HttpMethod.GET);
}
public default <T> Optional<T> get(String URL) {
return get(URL, Collections.EMPTY_MAP, ResponseParsers.STRING);
}
public default <T> Optional<T> get(String URL, boolean isAsync) {
return get(URL, Collections.EMPTY_MAP, ResponseParsers.STRING);
}
public default <T> Optional<T> get(String URL, Map params) {
return get(URL, params, ResponseParsers.STRING);
}
public default <T> Optional<T> get(String url, Map<String, String> params, ResponseParser<T> responseParser) {
return request(url, params, HttpMethod.GET, responseParser);
}
public default <T> Optional<T> get(String URL, ResponseParser<T> responseParser) {
return request(URL, Collections.EMPTY_MAP, HttpMethod.GET, responseParser);
}
public default <T> Optional<T> request(String url, Map params, HttpMethod httpMethod, ResponseParser<T> responseParser) {
return request(url, null, params, httpMethod, responseParser);
}
public <T> Optional<T> request(String url, HttpEntity entity, Map params, HttpMethod httpMethod, ResponseParser<T> responseParser);
HttpResponse execute(HttpUriRequest request, Closeable httpClient) ;
}
Below is my RestServiceBase
public abstract class RestServiceBase implements IRestService{
#Override
public <T> Optional<T> request(HttpMethod method) {
return Optional.empty();
}
#Override
public <T> Optional<T> request(String url, HttpEntity entity, Map params, HttpMethod httpMethod, ResponseParser<T> responseParser) {
T respose = null;
try {
final HttpUriRequest httpUriRequest = buildHttpUriRequest(httpMethod, url, entity, params);
respose = (T) request(httpUriRequest, responseParser);
} catch (HttpException | URISyntaxException e) {
e.printStackTrace();
}
return Optional.ofNullable(respose);
}
public <T> T request(HttpUriRequest request, final ResponseParser<T> responseParser) {
return call(request, new BaseResponseHandler<>(entity -> {
// Gets the content as a string
String content = entity != null ? EntityUtils.toString(entity, "UTF-8") : null;
// Parses the response
return responseParser.parse(content);
}));
}
private HttpUriRequest buildHttpUriRequest(HttpMethod httpMethod, String url, HttpEntity entity,
Map<String, String> params) throws HttpException, URISyntaxException {
URI uri = buildURI(url, params);
final RequestBuilder requestBuilder = resolveRequestBuilder(httpMethod,uri);
Optional.ofNullable(entity).ifPresent(requestBuilder::setEntity);
return requestBuilder.build();
}
private URI buildURI(String url, Map<String, String> params) throws URISyntaxException {
URIBuilder uriBuilder = new URIBuilder(url);
Optional.ofNullable(params.entrySet())
.ifPresent(map -> map.forEach(e -> uriBuilder.setParameter(e.getKey(), e.getValue())));
return uriBuilder.build();
}
private RequestBuilder resolveRequestBuilder(HttpMethod method, URI uri) throws HttpException {
switch (method) {
case GET:
return RequestBuilder.get().setUri(uri);
case PUT:
return RequestBuilder.put().setUri(uri);
case POST:
return RequestBuilder.post().setUri(uri);
case DELETE:
return RequestBuilder.delete().setUri(uri);
default:
throw new HttpException("Unsupported HttpMethod " + method);
}
}
}
Below is my RestService( which uses Synchronous version of Apache http client)
#Service
public class RestService extends RestServiceBase{
#Autowired
HttpClientFactory httpClientFactory;
public HttpResponse execute(HttpUriRequest request, Closeable httpClient) {
if(! (httpClient instanceof CloseableHttpClient))
throw new RuntimeException("UnSupported HttpClient Exception");
try {
CloseableHttpClient closeableHttpClient = (CloseableHttpClient) httpClient;
return closeableHttpClient.execute(request);
} catch (IOException e) {
throw new RuntimeException();
}
}
private CloseableHttpClient getHttpClient() {
ApacheHttpClient apacheHttpClient = (ApacheHttpClient) httpClientFactory.getApacheHttpClient();
return (CloseableHttpClient) apacheHttpClient.getHttpClient();
}
public <T> T call(HttpUriRequest request, ResponseHandler<T> responseHandler) {
try {
try (CloseableHttpClient httpClient = getHttpClient()) {
HttpResponse response = execute(request, httpClient);
// Entity response
HttpEntity entity = response.getEntity();
try {
return responseHandler.handleResponse(request, response, entity);
} finally {
EntityUtils.consume(entity);
}
}
} catch (IOException e) {
throw new ClientGeneralException(request, e);
} finally {
((HttpRequestBase) request).releaseConnection();
}
}
}
Below is my RestService( which uses Asynchronous version of Apache http client)
#Service
public class RestServiceAsync extends RestServiceBase{
#Autowired
HttpClientFactory httpClientFactory;
public HttpResponse execute(HttpUriRequest request, Closeable httpClient) {
if(! (httpClient instanceof CloseableHttpAsyncClient))
throw new RuntimeException("UnSupported HttpClient Exception");
try {
CloseableHttpAsyncClient closeableHttpClient = (CloseableHttpAsyncClient) httpClient;
Future<HttpResponse> future = closeableHttpClient.execute(request, null);
HttpResponse response = future.get();
return response;
//return (HttpResponse) closeableHttpClient.execute(request,null);
} catch (InterruptedException | ExecutionException e) {
request.abort();
throw new RuntimeException();
}
}
private CloseableHttpAsyncClient getHttpClient() {
ApacheAsyncClient apacheAsyncClient = (ApacheAsyncClient) httpClientFactory.getApacheAsyncHttpClient();
return (CloseableHttpClient) apacheAsyncClient.getHttpClient();
}
public <T> T call(HttpUriRequest request, ResponseHandler<T> responseHandler) {
try {
try (CloseableHttpAsyncClient httpClient = getHttpClient()) {
HttpResponse response = execute(request, httpClient);
// Entity response
HttpEntity entity = response.getEntity();
try {
return responseHandler.handleResponse(request, response, entity);
} finally {
EntityUtils.consume(entity);
}
}
} catch (IOException e) {
throw new ClientGeneralException(request, e);
} finally {
((HttpRequestBase) request).releaseConnection();
}
}
}
Below is my sample use case of RestServiceAsync
#Service
ReportsService(){
#Autowired
#Qualifier("restServiceAsync")
RestService restService;
public getReport(){
restService.get("http://localhost/reports");
}
}
I want to introduce Response read timeout so that main thread thats executing RestServiceAsync.execute method wont wait more than the desired amount of time for different use cases. Below were my approaches for doing this
1. Introduce a private timeout variable and use setter method in RestServiceAsync and do HttpResponse response = future.get(timeout, TimeUnit.Seconds);. This approach is not viable since RestServiceAsync is a singleton bean setting timeout variable would reflect for all the users of the application
2. Send timeout as a parameter from the method call as restService.get("http://localhost/reports",30); this would work but I have to update all the relevant methods in IRestService.
I am wondering if there is an alternative efficient approach to introduce timeout without having to touch all the methods in IRestService but making changes only in RestServiceAsync
PS: ApacheAsyncClient uses PoolingNHttpClientConnectionManager and ApacheHttpClient uses PoolingHttpClientConnectionManager

Related

Getting response null using pure Java

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 hours ago.
Improve this question
Using a pure Java,I try to send Get request and get response null.
Is there any bug in my code?
public static void TradeExchange() throws IOException, InterruptedException {
String urlString = "https://api.spimex.com/otc/lookup-tables/1";
HttpClient httpClient = new HttpClient() {
#Override
public Optional<CookieHandler> cookieHandler() {
return Optional.empty();
}
#Override
public Optional<Duration> connectTimeout() {
return Optional.empty();
}
#Override
public Redirect followRedirects() {
return null;
}
#Override
public Optional<ProxySelector> proxy() {
return Optional.empty();
}
#Override
public SSLContext sslContext() {
return null;
}
#Override
public SSLParameters sslParameters() {
return null;
}
#Override
public Optional<Authenticator> authenticator() {
return Optional.empty();
}
#Override
public Version version() {
return null;
}
#Override
public Optional<Executor> executor() {
return Optional.empty();
}
#Override
public <T> HttpResponse<T> send(HttpRequest httpRequest, HttpResponse.BodyHandler<T> bodyHandler) throws IOException, InterruptedException {
return null;
}
#Override
public <T> CompletableFuture<HttpResponse<T>> sendAsync(HttpRequest httpRequest, HttpResponse.BodyHandler<T> bodyHandler) {
return null;
}
#Override
public <T> CompletableFuture<HttpResponse<T>> sendAsync(HttpRequest httpRequest, HttpResponse.BodyHandler<T> bodyHandler, HttpResponse.PushPromiseHandler<T> pushPromiseHandler) {
return null;
}
};
HttpRequest httpRequest = HttpRequest.newBuilder(URI.create(urlString))
.GET()
.build();
try {
HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
String body = response.body();
} catch (IOException | InterruptedException e) {
System.out.println(e.getMessage());
}
}
I have no idea why you're implementing your own HttpClient with methods which return nulls and empty optionals and expect it to work properly.
Java already has an implementation of Http client, you just need to use it.
HttpClient client = HttpClient.newHttpClient();
or using builder:
HttpClient.newBuilder()
...
Examples from official docs
An article which covers how to use Java HttpClient
You can do something similar. Your code returns null because you didn't provide any implementation for your HTTP client.
String urlString = "https://api.spimex.com/otc/lookup-tables/1";
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest httpRequest = HttpRequest.newBuilder(URI.create(urlString))
.GET()
.build();
try {
HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
String responseBody = response.body();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
you should not implement you own HttpClient that returns nulls you can try this instead :
HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_1_1)
.connectTimeout(Duration.ofSeconds(10))
.build();

okhttp response.body().string() android.os.NetworkOnMainThreadExceptin [duplicate]

I want to use OkHttp library for networking in Android.
I started with the simple post example as written in their website:
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
With this call:
String response = post("http://www.roundsapp.com/post", json);
This call ends with NetworkOnMainThreadException.
I could wrap the call with an AsyncTask, but as far as I understand from the examples, the OkHttp library should have already taken care of that..
Am I doing something wrong?
You should use OkHttp's async method.
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
Call post(String url, String json, Callback callback) {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Call call = client.newCall(request);
call.enqueue(callback);
return call;
}
And then your response would be handled in the callback (OkHttp 2.x):
post("http://www.roundsapp.com/post", json, new Callback() {
#Override
public void onFailure(Request request, Throwable throwable) {
// Something went wrong
}
#Override public void onResponse(Response response) throws IOException {
if (response.isSuccessful()) {
String responseStr = response.body().string();
// Do what you want to do with the response.
} else {
// Request not successful
}
}
});
Or OkHttp 3.x/4.x:
post("http://www.roundsapp.com/post", "", new Callback() {
#Override
public void onFailure(Call call, IOException e) {
// Something went wrong
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String responseStr = response.body().string();
// Do what you want to do with the response.
} else {
// Request not successful
}
}
});
Take a look at their recipes for more examples: http://square.github.io/okhttp/recipes/
According to the OkHttp docs:
It supports both synchronous blocking calls and async calls with callbacks.
Your example is on main thread and Android since version 3.0 throws that exception if you try to do network calls on main thread
Better option is to use it together with retrofit and Gson:
http://square.github.io/retrofit/
https://code.google.com/p/google-gson/
Here are the examples:
http://engineering.meetme.com/2014/03/best-practices-for-consuming-apis-on-android/
http://heriman.net/?p=5
If you follows these steps to implement OKHTTP, then definitely you'll call multiple API on multiple screen by applying only two lines of code
UpdateListener updateListener = new UpdateListener(HitAPIActivity.this, baseHTTPRequest);
updateListener.getJsonData();
Step 1:
baseHTTPRequest = new BaseHTTPRequest();
// baseHTTPRequest.setURL("https://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demohttps://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo");
baseHTTPRequest.setURL("http://jsonparsing.parseapp.com/jsonData/moviesDemoItem.txt");
baseHTTPRequest.setRequestCode(reqType);
baseHTTPRequest.setCachedRequired(true);
UpdateListener updateListener = new UpdateListener(HitAPIActivity.this, baseHTTPRequest);
updateListener.executeRequest();
Step 2 : Create a request class
/**
* Created by Deepak Sharma on 4/7/16.
* This is a HTTP request class which has the basic parameters.
* If you wants to add some more parameters, please make a subclass of that class
* and add with your subclass. Don't modify this class.
*/
public class BaseHTTPRequest<T> {
private Context context;
private String URL;
private int requestCode;
private List<T> listParameters;
private String header;
private boolean isCachedRequired;
public Context getContext() {
return context;
}
public void setContext(Context context) {
this.context = context;
}
public void setURL(String URL) {
this.URL = URL;
}
public String getURL() {
return URL;
}
public int getRequestCode() {
return requestCode;
}
public void setRequestCode(int requestCode) {
this.requestCode = requestCode;
}
public List<T> getListParameters() {
return listParameters;
}
public void setListParameters(List<T> listParameters) {
this.listParameters = listParameters;
}
public String getHeader() {
return header;
}
public void setHeader(String header) {
this.header = header;
}
public boolean isCachedRequired() {
return isCachedRequired;
}
public void setCachedRequired(boolean cachedRequired) {
isCachedRequired = cachedRequired;
}
}
step 4 : Create a listener class
import android.util.Log;
import com.google.gson.Gson;
import java.io.IOException;
import dxswifi_direct.com.wifidirectcommunication.base.model.request.BaseHTTPRequest;
import okhttp3.Call;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* Created by Deepak Sharma on 4/7/16.
* #email : dpsharma.sharma1#gmail.com
* This is a Simple java class which will help you for HTTP request/response and it will
* throw the response to your correspondance activity.
*/
public class UpdateListener {
private OnUpdateViewListener onUpdateViewListener;
OkHttpClient okHttpClient = new OkHttpClient();
BaseHTTPRequest mRequestModel;
private String mURL = null;
private Request mRequest = null;
public interface OnUpdateViewListener {
void updateView(String responseString, boolean isSuccess,int reqType);
}
public UpdateListener(OnUpdateViewListener onUpdateView, final BaseHTTPRequest requestModel) {
this.mRequestModel = requestModel;
this.onUpdateViewListener = onUpdateView;
if (requestModel.isCachedRequired())
{
/*File httpCacheDirectory = new File(requestModel.getContext().getCacheDir(), "responses");
Cache cache = null;
cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024);
if (cache != null) {
okHttpClient.setCache(cache);
}*/
}
/*mURL = null;
if (requestModel.getListParameters()!=null && requestModel.getListParameters().size()>0)
{
HttpUrl.Builder urlBuilder = HttpUrl.parse(requestModel.getURL()).newBuilder();
List<RequestParameter> requestParameters = requestModel.getListParameters();
for (int i=0; i<requestParameters.size();i++)
{
urlBuilder.addQueryParameter(requestParameters.get(i).getKey(),requestParameters.get(i).getValue());
}
mURL = urlBuilder.build().toString();
}
else
{
mURL = requestModel.getURL();
}*/
mURL = requestModel.getURL();
if (mRequestModel.getListParameters()!=null && mRequestModel.getListParameters().size()>1)
{
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
mRequest = new Request.Builder()
.url(mURL)
.post(RequestBody.create(JSON, new Gson().toJson(BaseHTTPRequest.class)))
.build();
}
else
{
mRequest = new Request.Builder()
.url(mURL)
.build();
}
}
public void executeRequest()
{
Call call = okHttpClient.newCall(mRequest);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
onUpdateViewListener.updateView(NetworkException.getErrorMessage(e), false, mRequestModel.getRequestCode());
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
// You can also throw your own custom exception
throw new IOException("Unexpected code " + response);
} else {
Log.i("Response:",response.toString());
Log.i("Response body:",response.body().toString());
Log.i("Response message:",response.message());
onUpdateViewListener.updateView(response.body().string(),true, mRequestModel.getRequestCode());
}
// do something wih the result
}
});
}
}
step 5 : From the activity you requesting, implement listener
public class HitAPIActivity extends AppCompatActivity implements View.OnClickListener, UpdateListener.OnUpdateViewListener{
#Override
public void updateView(final String responseString, boolean isSuccess, int reqType) {
if (isSuccess)
{
if (!responseString.contains("failure")
&& !responseString.contains("Error")) {
// Handle request on the basis of Request Type.
switch (reqType) {
case ApiConstants.GET_CONTACTS:
break;
default:
break;
}
}
}
}

Does Apache Commons HttpAsyncClient support GZIP?

This question was asked for Apache Commons HttpClient, however I'm using the async client HttpAsyncClient.
Content decompression (gzip) does not work out of the box.
I tried to configure it with:
httpClientAsync = HttpAsyncClients.custom()
.setMaxConnPerRoute(100)
.setMaxConnTotal(200)
// Enable response content encoding (gzip)
//
// NOTE: Does not work for some reason
.addInterceptorLast(ResponseContentEncoding())
Which I copied from HttpClientBuilder, but it doesn't work.
Any ideas?
The use of addInterceptorLast and addInterceptorFirst has no effect.
asyncHttpClient.execute() will create a BasicAsyncResponseConsumer by default.
This BasicAsyncResponseConsumer will copy the original ContentDecoder into the buffer, resulting in DecompressingEntity.getContent() is never called.
org.apache.http.impl.nio.client.CloseableHttpAsyncClient#execute()
public Future<HttpResponse> execute(
final HttpHost target, final HttpRequest request, final HttpContext context,
final FutureCallback<HttpResponse> callback) {
return execute(
HttpAsyncMethods.create(target, request),
HttpAsyncMethods.createConsumer(), // BasicAsyncResponseConsumer
context, callback);
}
org.apache.http.nio.protocol.BasicAsyncResponseConsumer#onContentReceived
protected void onContentReceived(
final ContentDecoder decoder, final IOControl ioControl) throws IOException {
Asserts.notNull(this.buf, "Content buffer");
this.buf.consumeContent(decoder);
}
My solution is to manually call ResponseContentEncoding.process(resp, context) in the callback to reset the HttpEntity.
private static final ResponseContentEncoding responseContentEncoding = new ResponseContentEncoding();
HttpClientContext hcc = HttpClientContext.create();
asyncHttpClient.execute(bidreq, hcc, new FutureCallback<HttpResponse>() {
#Override
public void completed(HttpResponse result) {
HttpEntity entity = null;
String content = null;
try {
responseContentEncoding.process(result, hcc);
entity = result.getEntity();
if (entity != null) {
content = EntityUtils.toString(entity, UTF_8);
log.info(content);
}
} catch (Exception e) {
log.error("error", e);
} finally {
EntityUtils.consumeQuietly(entity);
}
}
#Override
public void failed(Exception ex) {
log.error("failed", ex);
}
#Override
public void cancelled() { }
});

Logging in Spring Boot - REST Controllers and WebClient

I'm creating a microservice using Spring Boot and i'm trying to develop my logging solution for it. Has of now i'm using this class for logging request/response.
#Component
#Slf4j
public class RequestAndResponseLoggingFilter implements Filter {
private static void logRequest(ContentCachingRequestWrapper request) {
String queryString = request.getQueryString();
if (queryString == null) {
log.info("{} {}", request.getMethod(), request.getRequestURI());
} else {
log.info("{} {}?{}", request.getMethod(), request.getRequestURI(), queryString);
}
Collections.list(request.getHeaderNames()).forEach(headerName ->
Collections.list(request.getHeaders(headerName)).forEach(headerValue ->
log.info("{}: {}", headerName, headerValue)));
byte[] content = request.getContentAsByteArray();
if (content.length > 0) {
logContent(content, request.getContentType(), request.getCharacterEncoding());
}
}
private static void logResponse(ContentCachingResponseWrapper response) {
int status = response.getStatus();
log.info("{} {}", status, HttpStatus.valueOf(status).getReasonPhrase());
response.getHeaderNames().forEach(headerName ->
response.getHeaders(headerName).forEach(headerValue ->
log.info("{}: {}", headerName, headerValue)));
byte[] content = response.getContentAsByteArray();
if (content.length > 0) {
logContent(content, response.getContentType(), response.getCharacterEncoding());
}
}
private static void logContent(byte[] content, String contentType, String contentEncoding) {
try {
String contentString = new String(content, contentEncoding);
contentString = contentString.replace("\n", "").replace("\t", "");
Stream.of(contentString.split("\r\n|\r|\n")).forEach(line -> log.info("{}", line));
} catch (UnsupportedEncodingException e) {
log.info("[{} bytes content]", content.length);
}
}
private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) {
if (request instanceof ContentCachingRequestWrapper) {
return (ContentCachingRequestWrapper) request;
} else {
return new ContentCachingRequestWrapper(request);
}
}
private static ContentCachingResponseWrapper wrapResponse(HttpServletResponse response) {
if (response instanceof ContentCachingResponseWrapper) {
return (ContentCachingResponseWrapper) response;
} else {
return new ContentCachingResponseWrapper(response);
}
}
#Override
public void init(FilterConfig filterConfig) {
log.info("Initializing Request and Response Logging Filter");
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
doFilterWrapped(wrapRequest(request), wrapResponse(response), filterChain);
}
#Override
public void destroy() {
}
protected void doFilterWrapped(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response,
FilterChain filterChain) throws ServletException, IOException {
try {
filterChain.doFilter(request, response);
} finally {
logRequestResponse(request, response);
response.copyBodyToResponse();
}
}
protected void logRequestResponse(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response) {
if (log.isInfoEnabled()) {
logRequest(request);
logResponse(response);
}
}
}
This class works fine for me: it prints the request and the respective response. My microservice makes REST calls to other microservices and for that
i use WebClient:
public testClient(ServiceConfig serviceConfig) {
this.webClient = WebClient.builder()
.filter(new TracingExchangeFilterFunction(GlobalTracer.get(),
Collections.singletonList(new WebClientSpanDecorator.StandardTags())))
.baseUrl(serviceConfig.getMockUri())
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
}
The problem is when i run my microservice the class responsible for the logging does not "catch" the request/response made by this WebClient instance.
1) Can you explain to me why this happens?
2) I also did a bit of search and i found a piece of code that can log the request made by the WebClient and that prints what i want to:
private ExchangeFilterFunction logRequest() {
return (clientRequest, next) -> {
logger.info("Request: {} {}", clientRequest.method(),
clientRequest.url());
clientRequest.headers()
.forEach((name, values) -> values.forEach(value -> logger.info("{}=
{}", name, value)));
return next.exchange(clientRequest);
};
}
Is there a way that i can use my logging class in my WebClient instance or do i need to write separate code for those two cases?

Is there a clean way to cancel an OkHttp 3 request when RxJava 2 Disposable is disposed?

So I've been trying to find a clean way of solving this issue for a while. Here's REST API class:
public class RestClient {
private final IJsonParser jsonParser;
private IServerUtils serverUtils;
private String baseApiUrl;
private OkHttpClient okHttpClient;
#Inject
public RestClient(OkHttpClient okHttpClient, IJsonParser jsonParser, IServerUtils serverUtils, #Named("baseApiUrl") String baseApiUrl) {
this.okHttpClient = okHttpClient;
this.jsonParser = jsonParser;
this.serverUtils = serverUtils;
this.baseApiUrl = baseApiUrl;
}
public Single<String> get(String route) {
if (serverUtils.isThereInternetConnection()) {
Request request = new Request.Builder()
.get()
.url(baseApiUrl + route)
.build();
final Call call = okHttpClient.newCall(request);
return Single.create(emitter -> {
execute(call, emitter);
});
} else {
return Single.error(new NetworkException());
}
}
public Single<String> post(String route, RequestBody requestBody) {
if (serverUtils.isThereInternetConnection()) {
Request request = new Request.Builder()
.post(requestBody)
.url(baseApiUrl + route)
.build();
final Call call = okHttpClient.newCall(request);
return Single.create(emitter -> execute(call, emitter));
} else {
return Single.error(new NetworkException());
}
}
public Single<String> postNoCache(String route, RequestBody requestBody) {
if (serverUtils.isThereInternetConnection()) {
Request request = new Request.Builder()
.post(requestBody)
.url(baseApiUrl + route)
.cacheControl(CacheControl.FORCE_NETWORK)
.build();
final Call call = okHttpClient.newCall(request);
return Single.create(emitter -> execute(call, emitter));
} else {
return Single.error(new NetworkException());
}
}
Response postRaw(String route, RequestBody requestBody) throws IOException {
Request request = new Request.Builder()
.post(requestBody)
.url(baseApiUrl + route)
.build();
return okHttpClient.newCall(request).execute();
}
public RequestBody convertHashMapToRequestBody(HashMap<String, String> params) {
FormBody.Builder builder = new FormBody.Builder();
for (String key : params.keySet()) {
builder.add(key, params.get(key));
}
return builder.build();
}
private void execute(Call call, SingleEmitter<String> emitter) throws IOException {
try {
Response response = call.execute();
String responseJson = response.body().string();
if (response.isSuccessful()) {
emitter.onSuccess(responseJson);
} else {
handleErrors(emitter, response, responseJson);
}
} catch (InterruptedIOException e) {
// This is my issue.
}
}
private void handleErrors(SingleEmitter<String> emitter, Response response, String responseJson) {
if (response.code() == 500 && responseJson != null) {
ApiError error = jsonParser.parseApiError(responseJson);
emitter.onError(new ApiException(error.getErrorMsg(), error.getError(), error.getUri()));
} else {
emitter.onError(new NetworkException("timeout"));
}
}
So in my execute() method I'd like to somehow maybe get some sort of callback when my upstream observer is destroyed, so I can cancel my network request. Currently what seems to happen is the thread that the Single is running on gets an interrupt, which throws an Exception, I'm not sure if this stops execution though. Is there a clean way of doing that? The only thing I've seen that you can do is the emitter.isDisposed(), which I can't see a normal usecase, since everything is synchronous in here and by the time I check that value it's most likely too late.
any help with this would be greatly appreciated.

Categories