package divconq.hub;
import java.net.IDN;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Pattern;
/**
* thanks Netty :)
*/
public class DomainNameMapping<V> {
protected static final Pattern DNS_WILDCARD_PATTERN = Pattern.compile("^\\*\\..*");
protected Map<String, V> map = new HashMap<>();
/*
* Adds a mapping that maps the specified (optionally wildcard) host name to the specified output value.
* <p>
* <a href="http://en.wikipedia.org/wiki/Wildcard_DNS_record">DNS wildcard</a> is supported as hostname.
* For example, you can use {@code *.netty.io} to match {@code netty.io} and {@code downloads.netty.io}.
* </p>
*/
public void add(String hostname, V di) {
map.put(normalizeHostname(hostname), di);
}
public void remove(String hostname) {
map.remove(normalizeHostname(hostname));
}
/*
public void dumpDomainNames() {
System.out.println("Domains: ");
System.out.println();
for (Entry<String, DomainInfo> en : this.map.entrySet()) {
System.out.println("Domain: " + en.getKey() + " - " + en.getValue().getId() + " : " + en.getValue().getTitle());
}
}
*/
/**
* Simple function to match <a href="http://en.wikipedia.org/wiki/Wildcard_DNS_record">DNS wildcard</a>.
*/
protected static boolean matches(String hostNameTemplate, String hostName) {
// note that inputs are converted and lowercased already
if (DNS_WILDCARD_PATTERN.matcher(hostNameTemplate).matches()) {
return hostNameTemplate.substring(2).equals(hostName) ||
hostName.endsWith(hostNameTemplate.substring(1));
}
else {
return hostNameTemplate.equals(hostName);
}
}
/**
* IDNA ASCII conversion and case normalization
*/
protected static String normalizeHostname(String hostname) {
if (needsNormalization(hostname))
hostname = IDN.toASCII(hostname, IDN.ALLOW_UNASSIGNED);
return hostname.toLowerCase(Locale.US);
}
protected static boolean needsNormalization(String hostname) {
int length = hostname.length();
for (int i = 0; i < length; i ++) {
int c = hostname.charAt(i);
if (c > 0x7F)
return true;
}
return false;
}
public V get(String name) {
if (name != null) {
name = normalizeHostname(name);
// prefer exact matches over wild
V exact = map.get(name);
if (exact != null)
return exact;
for (Map.Entry<String, V> entry : map.entrySet()) {
if (matches(entry.getKey(), name))
return entry.getValue();
}
}
return null;
}
}