package aQute.jsonrpc.proxy;
import java.io.*;
import java.lang.reflect.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import aQute.jsonrpc.domain.JSON.Request;
import aQute.jsonrpc.domain.JSON.Response;
import aQute.lib.collections.*;
import aQute.lib.converter.*;
import aQute.lib.hex.*;
import aQute.lib.json.*;
import aQute.rest.urlclient.*;
@SuppressWarnings("unchecked")
public class JSONRPCProxy implements InvocationHandler {
public static final String JSONRPC_2_0 = "jsonrpc/2.0/";
static AtomicLong counter = new AtomicLong(System.currentTimeMillis());
static JSONCodec codec = new JSONCodec();
static Converter converter = new Converter();
static ThreadLocal<Future< ? >> lastcall = new ThreadLocal<Future< ? >>();
static {
converter.hook(byte[].class, new Converter.Hook() {
@Override
public Object convert(Type dest, Object o) throws Exception {
if (o instanceof String) {
return Hex.toByteArray((String) o);
}
return null;
}
});
}
final URLClient host;
final String endpoint;
private final Executor executor;
private JSONRPCProxy(URLClient host, String endpoint, Executor executor) {
this.endpoint = endpoint;
this.host = host;
this.executor = executor;
}
public static <T> T createRPC(Class<T> interf, URLClient host, String endpoint) throws Exception {
return createRPC(interf, host, endpoint, null);
}
public static <T> T createRPC(Class<T> interf, URLClient host, String endpoint, Executor executor) throws Exception {
return (T) Proxy.newProxyInstance(interf.getClassLoader(), new Class[] {
interf
}, new JSONRPCProxy(host, endpoint, executor));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (executor != null)
return invokeAsync(proxy, method, args);
else
return invokeSync(proxy, method, args);
}
private <Y> Y invokeAsync(final Object proxy, final Method method, final Object[] args) throws Exception {
FutureTask<Y> task = new FutureTask<Y>(new Callable<Y>() {
@Override
public Y call() throws Exception {
try {
return invokeSync(proxy, method, args);
}
catch (Throwable e) {
throw new InvocationTargetException(e);
}
}
});
executor.execute(task);
lastcall.set(task);
return (Y) converter.convert(method.getGenericReturnType(), null);
}
private <Y> Y invokeSync(Object proxy, Method method, Object[] args) throws Exception {
Request request = new Request();
request.id = counter.incrementAndGet();
request.method = method.getName();
request.params = new ExtList<Object>(args);
Response response = host.put(JSONRPC_2_0 + endpoint, request, Response.class, null);
if (response == null)
throw new FileNotFoundException("Not found url endpoint: " + host.getUrl());
if (response.error != null)
throw new JSONRpcException(response.error);
if (method.getReturnType() == void.class || method.getReturnType() == Void.class || response.result == null)
return null;
return (Y) converter.convert(method.getGenericReturnType(), response.result);
}
public static <T> Future<T> async(T returnValue) {
return (Future<T>) lastcall.get();
}
}