package pl.icedev.rmi;
import org.json.simple.JSONObject;
import pl.icedev.nio.NIOFactory;
import pl.icedev.nio.NIOServer;
import pl.icedev.util.StringMap;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Map;
public class RMIServer implements NIOFactory<RMIConnection> {
NIOServer<RMIConnection> nio;
public RMIServer(InetSocketAddress addr) throws IOException {
nio = new NIOServer<>(addr, this);
}
public void update(int timeout) throws IOException {
nio.update(timeout);
}
@Override
public RMIConnection newConnection(SocketChannel channel, Selector selector) throws IOException {
return new RMIConnection(this, channel, selector);
}
Map<String, RMIInterface> interfaces = new HashMap<>();
public void registerInterface(Object obj) {
registerInterface(obj, obj.getClass());
}
public void registerInterface(Object obj, Class<?> clazz) {
RMIInterface interf = new RMIInterface(obj, clazz);
interfaces.put(clazz.getSimpleName(), interf);
}
class RMIInterface {
Object interf;
public RMIInterface(Object obj, Class<?> clazz) {
interf = obj;
if (!clazz.isInstance(obj))
throw new IllegalArgumentException("Interface object not sublass of interface, yo");
Method[] meth = clazz.getMethods();
for (Method m : meth) {
String signature = m.getName() + ";";
Class<?>[] params = m.getParameterTypes();
for (Class<?> type : params) {
signature += TypeUtil.getTypeChar(type);
}
Method old = methods.put(signature, m);
if (old != null) {
throw new IllegalArgumentException("Conflicting method signature: " + signature);
}
}
}
public Object invoke(String method, Object[] params) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
String signature = method + ";";
for (Object o : params) {
signature += TypeUtil.getTypeChar(o);
}
Method meth = methods.get(signature);
if (meth == null)
throw new NoSuchMethodException("No method with signature: " + signature);
// TODO process params
Class<?>[] types = meth.getParameterTypes();
for (int i = 0; i < params.length; i++) {
Class<?> type = types[i];
// json parser uses Double and Long by default
if (type == JSONObject.class) {
params[i] = new StringMap((JSONObject) params[i]);
} else if (type == Float.class || type == float.class) {
params[i] = TypeUtil.toFloat(params[i]);
} else if (type == Integer.class || type == int.class) {
params[i] = TypeUtil.toInt(params[i]);
} else if (type.isArray()) {
params[i] = TypeUtil.toArray(params[i], type.getComponentType());
}
}
Object result = meth.invoke(interf, params);
if (result instanceof StringMap) {
result = ((StringMap) result).getRawObject();
}
return result;
}
Map<String, Method> methods = new HashMap<>();
}
}