DS-Lab / src / main / java / dslab / client / MessageClient.java
MessageClient.java
Raw
package dslab.client;

import at.ac.tuwien.dsg.orvell.StopShellException;
import at.ac.tuwien.dsg.orvell.annotation.Command;
import dslab.ComponentFactory;
import dslab.authentication.AuthenticationException;
import dslab.crypto.MessageClientHash;
import dslab.mailbox.MessageNotFoundException;
import dslab.protocol.Message;
import dslab.protocol.dmap.MessageMetadata;
import dslab.protocol.dmtp.InvalidMessageException;
import dslab.protocol.dmtp.NoOpenMessageException;
import dslab.rmi.channel.SocketChannel;
import dslab.rmi.stub.dmap.DmapClientStub;
import dslab.routing.Address;
import dslab.routing.AddressResolutionException;
import dslab.util.ComponentId;
import dslab.util.Config;
import dslab.util.MessageClientConfig;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.nio.channels.ClosedChannelException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import static java.lang.Integer.parseInt;

public class MessageClient implements IMessageClient, Runnable {

    private final InputStream in;
    private final PrintStream out;
    private final ComponentFactory componentFactory;
    private final MessageClientConfig config;
    private final MessageClientHash hash;
    private static final Logger LOG = Logger.getLogger(MessageClient.class.getSimpleName());
    private DmapClientStub dmap;

    /**
     * Creates a new client instance.
     *
     * @param componentId the id of the component that corresponds to the Config resource
     * @param config      the component config
     * @param in          the input stream to read console input from
     * @param out         the output stream to write console output to
     */
    public MessageClient(String componentId, Config config, InputStream in, PrintStream out) {
        componentFactory = new ComponentFactory(new ComponentId(componentId), config);

        this.in = in;
        this.out = out;
        this.config = componentFactory.getMessageClientConfig();
        this.hash = new MessageClientHash();
    }

    public static void main(String[] args) throws Exception {
        IMessageClient client = ComponentFactory.createMessageClient(args[0], System.in, System.out);
        client.run();
    }

    @Override
    public void run() {

        dmap = componentFactory.getDmapClientStub();

        try {
            dmap.startsecure();
            dmap.login(config.mailboxUser(), config.mailboxPassword());
        } catch (AuthenticationException e) {
            throw new RuntimeException(
                    "The username " + config.mailboxUser() + " or the corresponding password was incorrect." +
                            "Check the credentials in the .properties file.", e);
        } catch (ClosedChannelException e) {
            LOG.log(Level.SEVERE, "Failed to set up connection to DMAP server", e);
        }
        componentFactory.createShell(this, in, out).run();
    }

    @Override
    @Command
    public void inbox() {
        try {
            List<MessageMetadata> list = dmap.list();
            for (MessageMetadata m : list) {
                out.println(m.getId() + "\n" + dmap.show(m.getId()).toGuiString());
            }
        } catch (AuthenticationException e) {
            throw new RuntimeException(e); //never happens
        } catch (MessageNotFoundException e) {
            out.println(e.getMessage());
        } catch (Exception e) {
            out.println(e.getMessage());
        }
    }

    @Override
    @Command
    public void delete(String id) {
        try {
            dmap.delete(parseInt(id));
            out.println("ok");
        } catch (AuthenticationException e) {
            throw new RuntimeException(e); //never happens
        } catch (MessageNotFoundException e) {
            out.println(e.getMessage());
        }
    }

    @Override
    @Command
    public void verify(String id) {

        try {
            out.println(hash.isValid(dmap.show(parseInt(id))) ? "ok" : "error invalid hash");
        } catch (MessageNotFoundException | NumberFormatException e) {
            out.println(e.getMessage());
        } catch (AuthenticationException e) {
            throw new RuntimeException(e); //never happens
        }
    }

    @Override
    @Command
    public void msg(String to, String subject, String data) {

        try {
            var socket = new Socket(config.transferHost(), config.transferPort());
            var channel = new SocketChannel(socket);
            var message = new Message();

            try (var dmtp = componentFactory.newDmtpInstance(channel)) {

                String[] raw = to.split(",");
                List<Address> rx = new ArrayList<>();
                for (String r : raw) {
                    rx.add(new Address(r));
                }

                message.setSender(config.transferEmail());
                message.setRecipients(rx);
                message.setSubject(subject);
                message.setData(data);

                dmtp.begin();
                dmtp.to(rx);
                dmtp.from(config.transferEmail());
                dmtp.subject(subject);
                dmtp.data(data);
                hash.calculateAndSet(message);
                dmtp.hash(message.getHash());
                dmtp.send();

                channel.close();
                socket.close();

            } catch (AddressResolutionException e) {
                channel.write("error address resolution failed");
            } catch (NoOpenMessageException e) {
                channel.write("error missing <begin>");
            } catch (InvalidMessageException e) {
                channel.write("error message build failed");
            }
        } catch (IOException e) {
            throw new RuntimeException(
                    "Couldn't establish a connection to the DMTP server. Are you sure it is running?");
        }
    }

    @Override
    @Command
    public void shutdown() {
        dmap.quit();
        this.componentFactory.shutdown();
        throw new StopShellException();
    }
}