DS-Lab / src / main / java / dslab / nameserver / NameserverRemote.java
NameserverRemote.java
Raw
package dslab.nameserver;

import dslab.routing.Domain;

import java.net.InetSocketAddress;
import java.rmi.RemoteException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

import static java.lang.Integer.parseInt;
import static java.util.Map.Entry.comparingByKey;
import static java.util.function.UnaryOperator.identity;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;

public class NameserverRemote implements INameserverRemote {

    private static final Logger LOG = Logger.getLogger(NameserverRemote.class.getSimpleName());
    private final Domain domain;

    private final Map<Domain, INameserverRemote> zones = new ConcurrentHashMap<>();
    private final Map<Domain, InetSocketAddress> mailboxServerAddresses = new ConcurrentHashMap<>();

    /**
     * This constructor exists to facilitate setup of tests
     *
     * @param domain of the zone this name server controls
     * @param zones  of domain
     */
    public NameserverRemote(Domain domain, Map<Domain, INameserverRemote> zones) {
        this(domain);
        this.zones.putAll(zones);
    }

    public NameserverRemote(String domain, Map<Domain, INameserverRemote> zones) {
        this(new Domain(domain), zones);
    }

    public NameserverRemote(String domain, Map<Domain, INameserverRemote> zones,
                            Map<Domain, InetSocketAddress> mailboxServers) {
        this(domain, zones);
        this.mailboxServerAddresses.putAll(mailboxServers);
    }

    /**
     * @param domain of the zone this name server controls
     */
    public NameserverRemote(Domain domain) {
        this.domain = domain;
    }

    public NameserverRemote(String domain) {
        this(new Domain(domain));
    }

    public <E> NameserverRemote(String domain, List<NameserverRemote> zones) {
        this(domain);
        this.zones.putAll(zones.stream().collect(toMap(NameserverRemote::getDomain, identity())));
    }

    Domain getDomain() {
        return domain;
    }

    public void registerNameserver(NameserverRemote nsRemote)
            throws AlreadyRegisteredException, InvalidDomainException, RemoteException {
        registerNameserver(nsRemote.getDomain().toString(), nsRemote);
    }

    @Override
    public void registerNameserver(String domainString, INameserverRemote nameserver)
            throws RemoteException, AlreadyRegisteredException, InvalidDomainException {

        var domain = new Domain(domainString);

        LOG.info("Registering name server '" + domainString + "' with " + this);

        if (domain.isLeaf()) {
            if (zones.containsKey(domain.getLast())) {
                throw new AlreadyRegisteredException("The zone " + domain.getLast() + " is already registered");
            } else {
                zones.put(domain.getLast(), nameserver);
            }
        } else {
            if ((zones.containsKey(domain.getLast()))) {
                zones.get(domain.getLast()).registerNameserver(domain.getInit().toString(), nameserver);
            } else {
                throw new InvalidDomainException("The zone " + domain.getLast() + " doesn't exist");
            }
        }
    }

    @Override
    public void registerMailboxServer(String domainString, String address)
            throws RemoteException, AlreadyRegisteredException, InvalidDomainException {

        LOG.info("Registering mailbox server '" + domainString + "' with " + this);


        var domain = new Domain(domainString);

        if (domain.isLeaf()) {
            var addressAndPort = address.split(":");
            var oldValue = mailboxServerAddresses.putIfAbsent(
                    domain.getLast(), new InetSocketAddress(addressAndPort[0], parseInt(addressAndPort[1])));
            if (oldValue != null)
                throw new AlreadyRegisteredException("The mail server " + domain.getLast() + " is already registered");

        } else {
            var remote = zones.get(domain.getLast());
            if (remote!=null) remote.registerMailboxServer(domain.getInit().toString(), address);
            else throw new InvalidDomainException("The zone " + domain.getLast() + " doesn't exist");
        }

    }

    @Override
    public INameserverRemote getNameserver(String zone) throws RemoteException {
        return zones.get(new Domain(zone));
    }

    /**
     * @return a string of format "<ip>:<port>" for the given leaf domain name, or null if no such domain exists
     */
    @Override
    public String lookup(String leafDomain) throws RemoteException {
        LOG.info("Nameserver for ’" + leafDomain + "’ requested by transfer server");

        var inetAddress = mailboxServerAddresses.get(new Domain(leafDomain));
        if (inetAddress == null) return null;
        return inetAddress.getAddress().getHostAddress() + ":" + inetAddress.getPort();
    }

    @Override
    public String toString() {
        return "NameserverRemote{" + domain + "}";
    }

    public String getMailboxServer(String subdomain) {
        var inetAddress = mailboxServerAddresses.get(new Domain(subdomain));
        return inetAddress.getAddress().getHostAddress() + ":" + inetAddress.getPort();

    }

    public List<Domain> getSortedZones() {
        return zones.keySet().stream().sorted().collect(toList());
    }

    public List<Entry<Domain, InetSocketAddress>> getMailboxserverAddresses() {
        return mailboxServerAddresses.entrySet()
                .stream()
                .sorted(comparingByKey())
                .collect(toList());
    }
}