package edu.uw.zookeeper; import static com.google.common.base.Preconditions.*; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import com.google.common.base.Splitter; import com.google.common.base.Supplier; import com.google.common.collect.Iterables; import edu.uw.zookeeper.data.Serializes; public class ServerInetAddressView implements Supplier<InetSocketAddress>, Comparable<ServerInetAddressView> { public static abstract class Address { public static final char TOKEN_SEP = ':'; private static final Splitter SPLITTER = Splitter.on(TOKEN_SEP).trimResults().limit(2); /** * Convert an InetSocketAddress to a String of the form "Address:Port". * * @param address InetSocketAddress to represent * @return "Address:Port" */ @Serializes public static String toString(InetSocketAddress address) { checkNotNull(address); // Prefer IP address, otherwise use the hostname String host; InetAddress ip = address.getAddress(); if (ip != null) { host = ip.getHostAddress(); } else { host = address.getHostName(); } return String.format("%s%c%d", host, TOKEN_SEP, address.getPort()); } /** * Convert a String the form "Address:Port" to an InetSocketAddress. * * A port of 0 directs the system to pick an ephemeral port. * An empty string is interpreted as ":0". * An empty address is interpreted as the wildcard address. * An address string can be either a hostname or an IP address. * * @param input "Address:Port" * @return InetSocketAddress representing input * @throws UnknownHostException */ @Serializes public static InetSocketAddress fromString(String input) throws UnknownHostException { checkNotNull(input); String[] fields = Iterables.toArray(SPLITTER.split(input), String.class); InetSocketAddress address; if (fields.length == 0) { address = new InetSocketAddress(0); } else { String portField = (fields.length > 1) ? fields[1] : fields[0]; int port = Integer.parseInt(portField); if (fields.length == 1) { address = new InetSocketAddress(port); } else { String field = fields[0]; if (field.equals("*")) { address = new InetSocketAddress(port); } else if (field.equals("localhost")) { address = new InetSocketAddress(InetAddress.getLocalHost(), port); } else { address = new InetSocketAddress(InetAddress.getByName(field), port); } } } return address; } private Address() {} } @Serializes public static ServerInetAddressView fromString(String input) throws UnknownHostException { return of(Address.fromString(input)); } @Serializes(to=EnsembleView.class) public static EnsembleView<ServerInetAddressView> ensembleFromString(String input) { return EnsembleView.copyOf(EnsembleView.fromString(input, ServerInetAddressView.class)); } /** * Wild-card address and ephemeral port. */ public static ServerInetAddressView ephemeral() { return unspecified(0); } /** * Wild-card address. */ public static ServerInetAddressView unspecified(int port) { return of(new InetSocketAddress(port)); } /** * Zero-length hostname is interpreted as the wild-card address. */ public static ServerInetAddressView of(String host, int port) { if (checkNotNull(host).length() == 0) { return unspecified(port); } else { return of(new InetSocketAddress(host, port)); } } public static ServerInetAddressView of(InetAddress addr, int port) { return of(new InetSocketAddress(addr, port)); } public static ServerInetAddressView of(InetSocketAddress address) { return new ServerInetAddressView(address); } private InetSocketAddress value; protected ServerInetAddressView(InetSocketAddress value) { this.value = value; } @Override public InetSocketAddress get() { return value; } @Override public int hashCode() { return get().hashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof ServerInetAddressView) { return get().equals(((ServerInetAddressView) obj).get()); } return false; } @Serializes @Override public String toString() { return Address.toString(get()); } @Override public int compareTo(ServerInetAddressView other) { return toString().compareTo(other.toString()); } }