package org.xnio.nio;
import java.io.Closeable;
import java.io.IOException;
import java.nio.channels.Selector;
import java.nio.channels.spi.SelectorProvider;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.xnio.FileSystemWatcher;
import org.xnio.IoUtils;
import org.xnio.Options;
import org.xnio.Xnio;
import org.xnio.OptionMap;
import org.xnio.XnioWorker;
import org.xnio.management.XnioProviderMXBean;
import org.xnio.management.XnioServerMXBean;
import org.xnio.management.XnioWorkerMXBean;
import static org.xnio.nio.Log.log;
final class NioXnio extends Xnio {
static final boolean IS_HP_UX;
static final boolean HAS_BUGGY_EVENT_PORT;
interface SelectorCreator {
Selector open() throws IOException;
}
final SelectorCreator tempSelectorCreator;
final SelectorCreator mainSelectorCreator;
static {
log.greeting(Version.getVersionString());
IS_HP_UX = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
final String bugLevel = System.getProperty("sun.nio.ch.bugLevel");
if (bugLevel == null) System.setProperty("sun.nio.ch.bugLevel", "");
return Boolean.valueOf(System.getProperty("os.name", "unknown").equalsIgnoreCase("hp-ux"));
}
}).booleanValue();
HAS_BUGGY_EVENT_PORT = true;
}
NioXnio() {
super("nio");
final Object[] objects = AccessController.doPrivileged(
new PrivilegedAction<Object[]>() {
public Object[] run() {
final SelectorProvider defaultProvider = SelectorProvider.provider();
final String chosenProvider = System.getProperty("xnio.nio.selector.provider");
SelectorProvider provider = null;
if (chosenProvider != null) {
try {
provider = Class.forName(chosenProvider, true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
provider.openSelector().close();
} catch (Throwable e) {
provider = null;
}
}
if (provider == null) {
try {
provider = Class.forName("sun.nio.ch.KQueueSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
provider.openSelector().close();
} catch (Throwable e) {
provider = null;
}
}
if (provider == null) {
try {
provider = Class.forName("sun.nio.ch.EPollSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
provider.openSelector().close();
} catch (Throwable e) {
provider = null;
}
}
if (provider == null && ! HAS_BUGGY_EVENT_PORT) {
try {
provider = Class.forName("sun.nio.ch.EventPortSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
provider.openSelector().close();
} catch (Throwable e) {
provider = null;
}
}
if (provider == null) {
try {
provider = Class.forName("sun.nio.ch.DevPollSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
provider.openSelector().close();
} catch (Throwable e) {
provider = null;
}
}
if (provider == null) {
try {
provider = Class.forName("sun.nio.ch.EventPortSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
provider.openSelector().close();
} catch (Throwable e) {
provider = null;
}
}
if (provider == null) {
try {
provider = Class.forName("sun.nio.ch.PollsetSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
provider.openSelector().close();
} catch (Throwable e) {
provider = null;
}
}
if (provider == null) {
try {
defaultProvider.openSelector().close();
provider = defaultProvider;
} catch (Throwable e) {
}
}
if (provider == null) {
try {
provider = Class.forName("sun.nio.ch.PollSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
provider.openSelector().close();
} catch (Throwable e) {
provider = null;
}
}
if (provider == null) {
throw log.noSelectorProvider();
}
log.selectorProvider(provider);
final boolean defaultIsPoll = "sun.nio.ch.PollSelectorProvider".equals(provider.getClass().getName());
final String chosenMainSelector = System.getProperty("xnio.nio.selector.main");
final String chosenTempSelector = System.getProperty("xnio.nio.selector.temp");
final SelectorCreator defaultSelectorCreator = new DefaultSelectorCreator(provider);
final Object[] objects = new Object[3];
objects[0] = provider;
if (chosenTempSelector != null) try {
final ConstructorSelectorCreator creator = new ConstructorSelectorCreator(chosenTempSelector, provider);
IoUtils.safeClose(creator.open());
objects[1] = creator;
} catch (Exception e) {
}
if (chosenMainSelector != null) try {
final ConstructorSelectorCreator creator = new ConstructorSelectorCreator(chosenMainSelector, provider);
IoUtils.safeClose(creator.open());
objects[2] = creator;
} catch (Exception e) {
}
if (! defaultIsPoll) {
if (objects[1] == null) try {
SelectorProvider pollSelectorProvider = Class.forName("sun.nio.ch.PollSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
pollSelectorProvider.openSelector().close();
objects[1] = new DefaultSelectorCreator(provider);
} catch (Exception e) {
}
}
if (objects[1] == null) {
objects[1] = defaultSelectorCreator;
}
if (objects[2] == null) {
objects[2] = defaultSelectorCreator;
}
return objects;
}
}
);
tempSelectorCreator = (SelectorCreator) objects[1];
mainSelectorCreator = (SelectorCreator) objects[2];
log.selectors(mainSelectorCreator, tempSelectorCreator);
register(new XnioProviderMXBean() {
public String getName() {
return "nio";
}
public String getVersion() {
return Version.getVersionString();
}
});
}
protected XnioWorker build(final XnioWorker.Builder builder) {
final NioXnioWorker worker = new NioXnioWorker(builder);
worker.start();
return worker;
}
@Override
public FileSystemWatcher createFileSystemWatcher(String name, OptionMap options) {
try {
boolean daemonThread = options.get(Options.THREAD_DAEMON, true);
return new WatchServiceFileSystemWatcher(name, daemonThread);
} catch (LinkageError e) {
}
return super.createFileSystemWatcher(name, options);
}
private final ThreadLocal<FinalizableSelectorHolder> selectorThreadLocal = new ThreadLocal<FinalizableSelectorHolder>() {
public void remove() {
FinalizableSelectorHolder holder = get();
if(holder != null) {
IoUtils.safeClose(holder.selector);
}
super.remove();
}
};
Selector getSelector() throws IOException {
final ThreadLocal<FinalizableSelectorHolder> threadLocal = selectorThreadLocal;
FinalizableSelectorHolder holder = threadLocal.get();
if (holder == null) {
holder = new FinalizableSelectorHolder(tempSelectorCreator.open());
threadLocal.set(holder);
}
return holder.selector;
}
private static class DefaultSelectorCreator implements SelectorCreator {
private final SelectorProvider provider;
private DefaultSelectorCreator(final SelectorProvider provider) {
this.provider = provider;
}
public Selector open() throws IOException {
return provider.openSelector();
}
public String toString() {
return "Default system selector creator for provider " + provider.getClass();
}
}
private static class ConstructorSelectorCreator implements SelectorCreator {
private final Constructor<? extends Selector> constructor;
private final SelectorProvider provider;
public ConstructorSelectorCreator(final String name, final SelectorProvider provider) throws ClassNotFoundException, NoSuchMethodException {
this.provider = provider;
final Class<? extends Selector> selectorImplClass = Class.forName(name, true, null).asSubclass(Selector.class);
final Constructor<? extends Selector> constructor = selectorImplClass.getDeclaredConstructor(SelectorProvider.class);
constructor.setAccessible(true);
this.constructor = constructor;
}
public Selector open() throws IOException {
try {
return constructor.newInstance(provider);
} catch (InstantiationException e) {
return Selector.open();
} catch (IllegalAccessException e) {
return Selector.open();
} catch (InvocationTargetException e) {
try {
throw e.getTargetException();
} catch (IOException | Error | RuntimeException e2) {
throw e2;
} catch (Throwable t) {
throw log.unexpectedSelectorOpenProblem(t);
}
}
}
public String toString() {
return String.format("Selector creator %s for provider %s", constructor.getDeclaringClass(), provider.getClass());
}
}
protected static Closeable register(XnioWorkerMXBean workerMXBean) {
return Xnio.register(workerMXBean);
}
protected static Closeable register(XnioServerMXBean serverMXBean) {
return Xnio.register(serverMXBean);
}
private static final class FinalizableSelectorHolder {
final Selector selector;
private FinalizableSelectorHolder(Selector selector) {
this.selector = selector;
}
@Override
protected void finalize() throws Throwable {
IoUtils.safeClose(selector);
}
}
}