com.outbrain.ob1k.client.ClientBuilder Maven / Gradle / Ivy
The newest version!
package com.outbrain.ob1k.client;
import com.outbrain.ob1k.HttpRequestMethodType;
import com.outbrain.ob1k.client.endpoints.AbstractClientEndpoint;
import com.outbrain.ob1k.client.endpoints.AsyncClientEndpoint;
import com.outbrain.ob1k.client.endpoints.StreamClientEndpoint;
import com.outbrain.ob1k.client.endpoints.SyncClientEndpoint;
import com.outbrain.ob1k.client.targets.EmptyTargetProvider;
import com.outbrain.ob1k.client.targets.TargetProvider;
import com.outbrain.ob1k.common.concurrent.ComposableFutureHelper;
import com.outbrain.ob1k.common.filters.AsyncFilter;
import com.outbrain.ob1k.Service;
import com.outbrain.ob1k.common.filters.ServiceFilter;
import com.outbrain.ob1k.common.filters.StreamFilter;
import com.outbrain.ob1k.common.filters.SyncFilter;
import com.outbrain.ob1k.http.common.ContentType;
import com.outbrain.ob1k.common.marshalling.RequestMarshallerRegistry;
import com.outbrain.ob1k.common.marshalling.TypeHelper;
import com.outbrain.ob1k.concurrent.ComposableFuture;
import com.outbrain.ob1k.http.HttpClient;
import com.outbrain.swinfra.metrics.api.MetricFactory;
import rx.Observable;
import java.io.Closeable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author aronen
*/
public class ClientBuilder {
private final Class type;
private final List syncFilters;
private final List asyncFilters;
private final List streamFilters;
private final Map endpointDescriptors;
private final HttpClient.Builder httpClientBuilder;
private TargetProvider targetProvider = new EmptyTargetProvider();
private ContentType clientType = ContentType.JSON;
public ClientBuilder(final Class type) {
this.type = type;
this.httpClientBuilder = new HttpClient.Builder();
this.syncFilters = new ArrayList<>();
this.asyncFilters = new ArrayList<>();
this.streamFilters = new ArrayList<>();
this.endpointDescriptors = new HashMap<>();
}
public ClientBuilder addFilter(final ServiceFilter filter) {
if (filter instanceof SyncFilter) {
syncFilters.add((SyncFilter) filter);
}
if (filter instanceof AsyncFilter) {
asyncFilters.add((AsyncFilter) filter);
}
if (filter instanceof StreamFilter) {
streamFilters.add((StreamFilter) filter);
}
return this;
}
public ClientBuilder setProtocol(final ContentType clientType) {
this.clientType = clientType;
return this;
}
public ClientBuilder followRedirect(final boolean followRedirect) {
httpClientBuilder.setFollowRedirect(followRedirect);
return this;
}
public ClientBuilder setMetricFactory(final MetricFactory metricFactory) {
httpClientBuilder.setMetricFactory(metricFactory);
return this;
}
public ClientBuilder setCompression(final boolean compression) {
httpClientBuilder.setCompressionEnforced(compression);
return this;
}
public ClientBuilder setMaxConnectionsPerHost(final int maxConnectionsPerHost) {
httpClientBuilder.setMaxConnectionsPerHost(maxConnectionsPerHost);
setTotalMaxConnections(maxConnectionsPerHost * 2);
return this;
}
public ClientBuilder setTotalMaxConnections(final int maxConnections) {
httpClientBuilder.setMaxTotalConnections(maxConnections);
return this;
}
public ClientBuilder setResponseMaxSize(final long responseMaxSize) {
httpClientBuilder.setResponseMaxSize(responseMaxSize);
return this;
}
public ClientBuilder setRetries(final int retries) {
httpClientBuilder.setRetries(retries);
return this;
}
public ClientBuilder setConnectionTimeout(final int timeout) {
httpClientBuilder.setConnectionTimeout(timeout);
return this;
}
public ClientBuilder setRequestTimeout(final int timeout) {
httpClientBuilder.setRequestTimeout(timeout);
return this;
}
public ClientBuilder setReadTimeout(final int timeout) {
httpClientBuilder.setReadTimeout(timeout);
return this;
}
public ClientBuilder setTargetProvider(final TargetProvider targetProvider) {
this.targetProvider = targetProvider == null ? new EmptyTargetProvider() : targetProvider;
return this;
}
public ClientBuilder bindEndpoint(final String methodName, final String path, final ServiceFilter... filters) {
bindEndpoint(methodName, HttpRequestMethodType.ANY, path, filters);
return this;
}
public ClientBuilder bindEndpoint(final String methodName, final HttpRequestMethodType requestMethodType) {
bindEndpoint(methodName, requestMethodType, methodName);
return this;
}
public ClientBuilder bindEndpoint(final String methodName, final HttpRequestMethodType requestMethodType,
final ServiceFilter... filters) {
bindEndpoint(methodName, requestMethodType, methodName, filters);
return this;
}
public ClientBuilder bindEndpoint(final String methodName, final ServiceFilter... filters) {
bindEndpoint(methodName, HttpRequestMethodType.ANY, methodName, filters);
return this;
}
public ClientBuilder bindEndpoint(final String methodName, final HttpRequestMethodType requestMethodType,
final String path, final ServiceFilter... filters) {
final List extends ServiceFilter> serviceFilters;
if (filters == null) {
serviceFilters = new ArrayList<>();
} else {
serviceFilters = Arrays.asList(filters);
}
endpointDescriptors.put(methodName, new EndpointDescriptor(methodName, path, serviceFilters, requestMethodType));
return this;
}
public T build() {
final ClassLoader loader = ClientBuilder.class.getClassLoader();
final HttpClient httpClient = httpClientBuilder.build();
final Map endpoints = extractEndpointsFromType(httpClient);
final HttpInvocationHandler handler = new HttpInvocationHandler(targetProvider, httpClient, endpoints);
@SuppressWarnings("unchecked")
final T proxy = (T) Proxy.newProxyInstance(loader, new Class[]{type, Closeable.class}, handler);
return proxy;
}
private static RequestMarshallerRegistry createRegistry(final Class type) {
final RequestMarshallerRegistry registry = new RequestMarshallerRegistry();
final Method[] methods = type.getDeclaredMethods();
for (final Method method : methods) {
registry.registerTypes(TypeHelper.extractTypes(method));
}
return registry;
}
private Map extractEndpointsFromType(final HttpClient httpClient) {
final Map endpoints = new HashMap<>();
final Method[] methods = type.getDeclaredMethods();
for (final Method method : methods) {
if (isValidEndpoint(method)) {
final String methodName = method.getName();
final EndpointDescriptor endpointDescriptor = getEndpointDescriptor(methodName);
final RequestMarshallerRegistry registry = createRegistry(type);
final AbstractClientEndpoint.Endpoint endpoint = new AbstractClientEndpoint.Endpoint(method, type, clientType,
endpointDescriptor.path, endpointDescriptor.requestMethodType);
final AbstractClientEndpoint clientEndpoint;
if (isAsync(method)) {
final List filters = mergeFilters(AsyncFilter.class, asyncFilters, endpointDescriptor.filters);
clientEndpoint = new AsyncClientEndpoint(httpClient, registry, endpoint, filters.toArray(new AsyncFilter[filters.size()]));
} else if (isStreaming(method)) {
final List filters = mergeFilters(StreamFilter.class, streamFilters, endpointDescriptor.filters);
clientEndpoint = new StreamClientEndpoint(httpClient, registry, endpoint, filters.toArray(new StreamFilter[filters.size()]));
} else {
final List filters = mergeFilters(SyncFilter.class, syncFilters, endpointDescriptor.filters);
clientEndpoint = new SyncClientEndpoint(httpClient, registry, endpoint, filters.toArray(new SyncFilter[filters.size()]));
}
endpoints.put(method, clientEndpoint);
}
}
return endpoints;
}
private EndpointDescriptor getEndpointDescriptor(final String methodName) {
return endpointDescriptors.containsKey(methodName) ?
endpointDescriptors.get(methodName) :
new EndpointDescriptor(methodName, methodName, null, HttpRequestMethodType.ANY);
}
private boolean isValidEndpoint(final Method method) {
final int modifiers = method.getModifiers();
return Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers);
}
private static List mergeFilters(final Class filterType, final List baseFilters,
final List extends ServiceFilter> specificFilters) {
final List filters = new ArrayList<>();
filters.addAll(baseFilters);
if (specificFilters != null) {
for (final ServiceFilter filter : specificFilters) {
if (filter instanceof AsyncFilter) {
filters.add(filterType.cast(filter));
}
}
}
return filters;
}
private static boolean isAsync(final Method method) {
return ComposableFutureHelper.isComposableFuture(method.getReturnType());
}
private static boolean isStreaming(final Method method) {
return method.getReturnType() == Observable.class;
}
/**
* Describes how endpoint of service looks for the client builder
*
* @author marenzon
*/
private class EndpointDescriptor {
public final String method;
public final String path;
public final List extends ServiceFilter> filters;
public final HttpRequestMethodType requestMethodType;
public EndpointDescriptor(final String method, final String path, final List extends ServiceFilter> filters,
final HttpRequestMethodType requestMethodType) {
this.method = method;
this.path = path;
this.filters = filters;
this.requestMethodType = requestMethodType;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy