package com.theotherian.dns;
import java.security.Security;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.log4j.Logger;
/**
* Initializes the thread local settings for your application. Make sure one of this type's initialize methods
* is the first thing called in your application, or at least the first thing called before DNS is
* initialized.<br>
* If you try to initialize the thread local DNS settings after DNS has initialized, the settings
* will not be detected.
* @author isimpson
*/
public final class ThreadLocalDns {
private static final Logger LOGGER = Logger.getLogger(ThreadLocalDns.class);
private static volatile boolean initialized = false;
private static final ExecutorService threadPool = Executors.newCachedThreadPool(new ThreadLocalDnsFactory());
/**
* Run the provided context inside of an thread local DNS configuration that is inheritable so
* that all threads spawned in the context have the same configuration.
* @param configuration
* @param context
*/
public static void executeContext(final ThreadLocalDnsConfiguration configuration,
final ThreadLocalDnsContext context) {
threadPool.submit(new Runnable() {
@Override
public void run() {
try {
OverrideNameService nameService = new OverrideNameService(configuration.getMappings());
OverrideNameServiceManager.initializeForThread(nameService);
OverrideNameServiceManager.initializeCache();
nameService.validate();
context.execute();
} catch (Throwable t) {
LOGGER.fatal("Context failed to start", t);
}
}
});
}
/**
* Initialize all system properties required for overriding DNS.
* @throws RuntimeException if you try to initialize twice
*/
public static void initialize() {
initialize(DnsConfigurationBuilder.newBuilder().build());
}
/**
* Initialize all system properties required for overriding DNS, and set a configuration for the main
* thread and all children of the main thread not created by the
* {@link #executeContext(ThreadLocalDnsConfiguration, ThreadLocalDnsContext)} method, which accepts its own
* configuration
* @param configuration
*/
public static void initialize(ThreadLocalDnsConfiguration configuration) {
if (!initialized) {
LOGGER.info("Initializing thread local DNS settings");
ThreadLocalDnsDescriptor descriptor = new ThreadLocalDnsDescriptor();
String provider = descriptor.getType() + "," + descriptor.getProviderName();
System.setProperty("sun.net.spi.nameservice.provider.1", provider);
Security.setProperty("networkaddress.cache.ttl", "0");
OverrideNameService nameService = new OverrideNameService(configuration.getMappings());
OverrideNameServiceManager.initializeForThread(nameService);
initialized = true;
}
else {
throw new RuntimeException("You can't initialize DNS twice in an application");
}
}
private static class ThreadLocalDnsFactory implements ThreadFactory {
private AtomicInteger counter = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "ThreadLocalDnsWorker-" + counter.getAndIncrement());
}
}
}