com.sdklite.rpc.RpcServiceProxy Maven / Gradle / Ivy
package com.sdklite.rpc;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import com.sdklite.rpc.annotation.DnsResolution;
import com.sdklite.rpc.annotation.Interception;
import com.sdklite.rpc.annotation.Timeout;
final class RpcServiceProxy implements InvocationHandler {
private static final Set OBJECT_METHODS = Collections.unmodifiableSet(new HashSet(Arrays.asList(Object.class.getMethods())));
final RpcServiceFactory factory;
final Class extends RpcService> service;
final String baseUrl;
final Set methods;
public RpcServiceProxy(final RpcServiceFactory factory, final Class extends RpcService> service, final String baseUrl) {
this.factory = factory;
this.service = service;
this.baseUrl = baseUrl;
this.methods = Collections.unmodifiableSet(new HashSet(Arrays.asList(service.getMethods())));
}
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
final String name = method.getName();
final Class>[] parameterTypes = method.getParameterTypes();
if (this.methods.contains(method)) {
return execute(method, args);
}
if (OBJECT_METHODS.contains(method)) {
if ("equals".equals(name) && Arrays.equals(new Class>[] { Object.class }, parameterTypes)) {
return this.equals(args[0]);
}
if ("hashCode".equals(name) && parameterTypes.length == 0) {
return this.hashCode();
}
if ("toString".equals(name) && parameterTypes.length == 0) {
return this.toString();
}
}
throw new NoSuchMethodException(method.toString());
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private Object execute(final Method method, final Object... args) throws RpcException {
try {
final RpcClient.Builder clientBuilder = getRpcClient(method, args).newBuilder();
// Set RPC timeout
final Timeout timeout = method.isAnnotationPresent(Timeout.class)
? method.getAnnotation(Timeout.class)
: this.service.getAnnotation(Timeout.class);
if (null != timeout) {
clientBuilder.setConnectTimeout(timeout.connectTimeout());
clientBuilder.setReadTimeout(timeout.readTimeout());
clientBuilder.setWriteTimeout(timeout.writeTimeout());
}
// Set RPC DNS resolver
final DnsResolution dns = method.isAnnotationPresent(DnsResolution.class)
? method.getAnnotation(DnsResolution.class)
: this.service.getAnnotation(DnsResolution.class);
if (null != dns) {
clientBuilder.setDnsResolver(dns.value().newInstance());
}
// Set RPC interceptors
final Interception interception = method.isAnnotationPresent(Interception.class)
? method.getAnnotation(Interception.class)
: this.service.getAnnotation(Interception.class);
if (null != interception) {
for (final Class extends RpcInterceptor> clazz : interception.value()) {
if (null != clazz) {
clientBuilder.addInterceptor(clazz.newInstance());
}
}
}
final RpcClient client = clientBuilder.build();
final RpcRequest request = client.newRequestBuilder()
.setUrl(this.baseUrl)
.setService(this.service, method, args)
.build();
final Rpc rpc = client.newRpc(request);
final Object result;
if (args.length > 0 && args[args.length - 1] instanceof RpcService.Callback) {
final RpcService.Callback callback = (RpcService.Callback) args[args.length - 1];
result = rpc.enqueue(new Rpc.Callback() {
@Override
public void onSuccess(final RpcResponse response) {
try {
callback.onSuccess(response.getContent());
} catch (final IOException e) {
callback.onFailure(new RpcException(e));
}
}
@Override
public void onFailure(final RpcRequest request, final RpcException e) {
callback.onFailure(e);
}
});
} else {
result = rpc.execute().getContent();
}
final Class> retType = method.getReturnType();
if (void.class.equals(retType) || Void.class.equals(retType)) {
return null;
}
return result;
} catch (final RpcException e) {
throw e;
} catch (final Throwable e) {
throw new RpcException(e);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private RpcClient getRpcClient(final Method method, final Object... args) throws Throwable {
final URI uri = new URI(this.baseUrl);
final RpcClient client = this.factory.getRpcClient(uri.getScheme());
if (!method.isAnnotationPresent(Interception.class)) {
return client;
}
final Interception interception = method.getAnnotation(Interception.class);
final Class extends RpcInterceptor>[] classesOfInterceptor = interception.value();
final RpcClient.Builder builder = client.newBuilder();
for (final Class extends RpcInterceptor> clazz : classesOfInterceptor) {
builder.addInterceptor(clazz.newInstance());
}
return builder.build();
}
}