package dslab.rmi.stub; import dslab.protocol.Protocol; import dslab.protocol.ProtocolException; import dslab.rmi.channel.SocketChannel; import dslab.rmi.serialize.ClientSerializer; import dslab.rmi.serialize.Executors.ThrowingSupplier; import dslab.rmi.serialize.ParseException; import java.io.Closeable; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.nio.channels.ClosedChannelException; import java.util.logging.Logger; public abstract class ClientStub<PROTOCOL extends Protocol> implements Closeable, InvocationHandler { private final Logger LOG = Logger.getLogger(getClass().getSimpleName()); protected final SocketChannel channel; private final ClientSerializer serializer; public ClientStub(SocketChannel channel, ClientSerializer serializer) { this.channel = channel; this.serializer = serializer; assertServerSpeaksProtocol(); } protected ThrowingSupplier<?, ? extends ProtocolException> call(Enum<?> command, Object args) { try { channel.write(serializer.serialize(command, args)); return serializer.deserialize(channel.readLinesWhileReady()); } catch (ClosedChannelException e) { throw new IllegalStateException(e); } catch (ParseException e) { throw new IllegalStateException("Could not parse server response", e); } } protected abstract String getProtocolName(); protected void assertServerSpeaksProtocol() throws IllegalStateException { try { var opener = channel.readLinesWhileReady(); if (!("ok " + getProtocolName()).equals(opener)) { throw new IllegalStateException("The server doesn't appear to speak " + getProtocolName() + ". " + "Its opener was '" + opener + "' instead of 'ok " + getProtocolName() + "'"); } } catch (ClosedChannelException e) { throw new IllegalStateException(e); } } @Override public void close() throws IOException { channel.close(); } }