package com.aol.micro.server.rest.client.nio;
import java.util.concurrent.CompletableFuture;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.InvocationCallback;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.experimental.Wither;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import com.aol.micro.server.rest.jackson.JacksonFeature;
import com.aol.micro.server.rest.jackson.JacksonUtil;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
@Wither
@Builder
@AllArgsConstructor
public class AsyncRestClient<T> {
private final Client client;
private final String contentType;
private final String accept;
private final Class<T> response;
private final JavaType genericResponse;
public AsyncRestClient(int readTimeout, int connectTimeout) {
this.client = initClient(readTimeout, connectTimeout);
contentType = MediaType.APPLICATION_JSON;
accept = MediaType.APPLICATION_JSON;
response = (Class<T>) String.class;
genericResponse = null;
}
public <R> AsyncRestClient<R> withResponse(Class<R> response) {
return new AsyncRestClient<R>(client, contentType, accept, response,null);
}
public <R> AsyncRestClient<R> withGenericResponse(Class<R> responseClass, Class... genericResponse) {
return new AsyncRestClient<R>(client, contentType, accept, null,JacksonUtil.getMapper().getTypeFactory().constructParametricType(responseClass,genericResponse));
}
protected Client initClient(int rt, int ct) {
ClientConfig clientConfig = new ClientConfig();
clientConfig.property(ClientProperties.CONNECT_TIMEOUT, ct);
clientConfig.property(ClientProperties.READ_TIMEOUT, rt);
ClientBuilder.newBuilder().register(JacksonFeature.class);
Client client = ClientBuilder.newClient(clientConfig);
client.register(JacksonFeature.class);
JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider();
provider.setMapper(JacksonUtil.getMapper());
client.register(provider);
return client;
}
public CompletableFuture<T> get(final String url) {
CompletableFuture<T> result = new CompletableFuture();
client.target(url).request(accept).accept(accept).async()
.get(new InvocationCallback<String>() {
@Override
public void completed(String complete) {
buildResponse(result, complete);
}
@Override
public void failed(Throwable ex) {
result.completeExceptionally(ex);
}
});
return result;
}
private void buildResponse(CompletableFuture<T> result,
String complete) {
if(normalNotGenericResponseType()){
if (shouldJustReturnString()){
thenJustReturnString(result, complete);
}
else{
convertToStandardEntity(result, complete);
}
} else
convertToGenericEntity(result, complete);
}
private void convertToGenericEntity(CompletableFuture<T> result,
String complete) {
result.complete((T) JacksonUtil.convertFromJson(
complete, genericResponse));
}
private void convertToStandardEntity(CompletableFuture<T> result,
String complete) {
result.complete((T) JacksonUtil.convertFromJson(
complete, response));
}
private void thenJustReturnString(CompletableFuture<T> result,
String complete) {
result.complete((T) complete);
}
private boolean shouldJustReturnString() {
return String.class.equals(response);
}
private boolean normalNotGenericResponseType() {
return this.genericResponse==null;
}
public <V> CompletableFuture<T> post(final String queryResourceUrl,
final V request) {
CompletableFuture<T> result = new CompletableFuture();
final WebTarget webResource = client.target(queryResourceUrl);
webResource
.request(accept)
.accept(accept)
.async()
.post(Entity.entity(request, contentType),
new InvocationCallback<String>() {
@Override
public void completed(String complete) {
buildResponse(result,complete);
}
@Override
public void failed(Throwable ex) {
result.completeExceptionally(ex);
}
});
return result;
}
public <V> CompletableFuture<T> put(final String queryResourceUrl,
final V request) {
CompletableFuture<T> result = new CompletableFuture<>();
final WebTarget webResource = client.target(queryResourceUrl);
webResource
.request(accept)
.accept(accept)
.async()
.put(Entity.entity(request, contentType),
new InvocationCallback<String>() {
@Override
public void completed(String complete) {
buildResponse(result,complete);
}
@Override
public void failed(Throwable ex) {
result.completeExceptionally(ex);
}
});
return result;
}
public CompletableFuture<T> delete(final String queryResourceUrl) {
CompletableFuture<T> result = new CompletableFuture<>();
final WebTarget webResource = client.target(queryResourceUrl);
webResource
.request(accept)
.accept(accept)
.async()
.delete(new InvocationCallback<String>() {
@Override
public void completed(String complete) {
buildResponse(result,complete);
}
@Override
public void failed(Throwable ex) {
result.completeExceptionally(ex);
}
});
return result;
}
}