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 zones = new ConcurrentHashMap<>(); private final Map 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 zones) { this(domain); this.zones.putAll(zones); } public NameserverRemote(String domain, Map zones) { this(new Domain(domain), zones); } public NameserverRemote(String domain, Map zones, Map 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 NameserverRemote(String domain, List 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 ":" 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 getSortedZones() { return zones.keySet().stream().sorted().collect(toList()); } public List> getMailboxserverAddresses() { return mailboxServerAddresses.entrySet() .stream() .sorted(comparingByKey()) .collect(toList()); } }