DS-Lab / src / main / java / dslab / rmi / stub / ClientStub.java
ClientStub.java
Raw
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();
    }
}