package one.nio.rpc;
import one.nio.net.ConnectionString;
import one.nio.net.Socket;
import one.nio.pool.SocketPool;
import one.nio.serial.CalcSizeStream;
import one.nio.serial.DataStream;
import one.nio.serial.DeserializeStream;
import one.nio.serial.Repository;
import one.nio.serial.SerializeStream;
import one.nio.serial.Serializer;
import one.nio.serial.SerializerNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.SocketException;
public class RpcClient extends SocketPool implements InvocationHandler {
public RpcClient(ConnectionString conn) throws IOException {
super(conn, 0);
}
public Object invoke(Object request) throws Exception {
byte[] buffer = invokeRaw(request);
for (;;) {
Object response;
try {
response = new DeserializeStream(buffer).readObject();
} catch (SerializerNotFoundException e) {
long uid = e.getUid();
Repository.provideSerializer(requestSerializer(uid));
continue;
}
if (!(response instanceof Exception)) {
return response;
} else if (response instanceof SerializerNotFoundException) {
long uid = ((SerializerNotFoundException) response).getUid();
provideSerializer(Repository.requestSerializer(uid));
buffer = invokeRaw(request);
} else {
throw (Exception) response;
}
}
}
@Override
public Object invoke(Object proxy, Method method, Object... args) throws Exception {
return invoke(new RemoteCall(method, args));
}
protected void provideSerializer(Serializer serializer) throws Exception {
invokeServiceRequest(new RemoteCall(Repository.provide, serializer));
}
protected Serializer requestSerializer(long uid) throws Exception {
return (Serializer) invokeServiceRequest(new RemoteCall(Repository.request, uid));
}
protected Object invokeServiceRequest(Object request) throws Exception {
byte[] rawResponse = invokeRaw(request);
Object response = new DeserializeStream(rawResponse).readObject();
if (response instanceof Exception) {
throw (Exception) response;
}
return response;
}
private byte[] invokeRaw(Object request) throws Exception {
byte[] buffer = serialize(request);
Socket socket = borrowObject();
try {
try {
sendRequest(socket, buffer);
} catch (SocketException e) {
// Stale connection? Retry on a fresh socket
destroyObject(socket);
socket = createObject();
sendRequest(socket, buffer);
}
int responseSize = RpcPacket.getSize(buffer, socket);
if (responseSize > 4) buffer = new byte[responseSize];
socket.readFully(buffer, 0, responseSize);
returnObject(socket);
return buffer;
} catch (Exception e) {
invalidateObject(socket);
throw e;
}
}
private byte[] serialize(Object request) throws IOException {
CalcSizeStream css = new CalcSizeStream();
css.writeObject(request);
int requestSize = css.count();
byte[] buffer = new byte[requestSize + 4];
DataStream ds = css.hasCycles() ? new SerializeStream(buffer) : new DataStream(buffer);
ds.writeInt(requestSize);
ds.writeObject(request);
return buffer;
}
private void sendRequest(Socket socket, byte[] buffer) throws IOException {
socket.writeFully(buffer, 0, buffer.length);
socket.readFully(buffer, 0, 4);
}
}