All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xnio.nio.NioXnio Maven / Gradle / Ivy

There is a newer version: 3.8.16.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source
 *
 * Copyright 2014 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


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;

/**
 * An NIO-based XNIO provider for a standalone application.
 */
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() {
            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();
        // if a JDK is released with a fix, we can try to detect it and set this to "false" for those JDKs.
        HAS_BUGGY_EVENT_PORT = true;
    }

    /**
     * Construct a new NIO-based XNIO provider instance.  Should only be invoked by the service loader.
     */
    NioXnio() {
        super("nio");
        final Object[] objects = AccessController.doPrivileged(
            new PrivilegedAction() {
                public Object[] run() {
                    String jdkVersion = System.getProperty("java.specification.version", "1.8");
                    final boolean jdk9 = ! (jdkVersion.equals("1.8") || jdkVersion.equals("8"));
                    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) {
                            // not available
                            provider = null;
                        }
                    }
                    if (! jdk9) {
                        // try to probe the best available provider
                        if (provider == null) {
                            try {
                                // Mac OS X and BSD
                                provider = Class.forName("sun.nio.ch.KQueueSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
                                provider.openSelector().close();
                            } catch (Throwable e) {
                                // not available
                                provider = null;
                            }
                        }
                        if (provider == null) {
                            try {
                                // Linux
                                provider = Class.forName("sun.nio.ch.EPollSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
                                provider.openSelector().close();
                            } catch (Throwable e) {
                                // not available
                                provider = null;
                            }
                        }
                        if (provider == null && ! HAS_BUGGY_EVENT_PORT) {
                            try {
                                // Solaris (Java 8+)
                                provider = Class.forName("sun.nio.ch.EventPortSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
                                provider.openSelector().close();
                            } catch (Throwable e) {
                                // not available
                                provider = null;
                            }
                        }
                        if (provider == null) {
                            try {
                                // Solaris
                                provider = Class.forName("sun.nio.ch.DevPollSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
                                provider.openSelector().close();
                            } catch (Throwable e) {
                                // not available
                                provider = null;
                            }
                        }
                        if (provider == null) {
                            try {
                                // Solaris (Java 8+)
                                provider = Class.forName("sun.nio.ch.EventPortSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
                                provider.openSelector().close();
                            } catch (Throwable e) {
                                // not available
                                provider = null;
                            }
                        }
                        if (provider == null) {
                            try {
                                // AIX
                                provider = Class.forName("sun.nio.ch.PollsetSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
                                provider.openSelector().close();
                            } catch (Throwable e) {
                                // not available
                                provider = null;
                            }
                        }
                    }
                    if (provider == null) {
                        try {
                            defaultProvider.openSelector().close();
                            provider = defaultProvider;
                        } catch (Throwable e) {
                            // not available
                        }
                    }
                    if (provider == null) {
                        try {
                            // Nothing else works, not even the default
                            provider = Class.forName("sun.nio.ch.PollSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance();
                            provider.openSelector().close();
                        } catch (Throwable e) {
                            // not available
                            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) {
                        // not available
                    }
                    if (chosenMainSelector != null) try {
                        final ConstructorSelectorCreator creator = new ConstructorSelectorCreator(chosenMainSelector, provider);
                        IoUtils.safeClose(creator.open());
                        objects[2] = creator;
                    } catch (Exception e) {
                        // not available
                    }
                    if (! defaultIsPoll && ! jdk9) {
                        // default is fine for main selectors; we should try to get poll for temp though
                        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) {
                            // not available
                        }
                    }
                    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) {
            //ignore
        }
        return super.createFileSystemWatcher(name, options);
    }

    @Override
    protected void handleThreadExit() {
        log.tracef("Invoke selectorThreadLocal.remove() on Thread [%s] exits", Thread.currentThread().getName());
        selectorThreadLocal.remove();
        super.handleThreadExit();
    }

    private final ThreadLocal selectorThreadLocal = new ThreadLocal() {
        public void remove() {
            // if no selector was created, none will be closed
            FinalizableSelectorHolder holder = get();
            if(holder != null) {
                IoUtils.safeClose(holder.selector);
            }
            super.remove();
        }
    };

    Selector getSelector() throws IOException {
        final ThreadLocal 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 constructor;
        private final SelectorProvider provider;

        public ConstructorSelectorCreator(final String name, final SelectorProvider provider) throws ClassNotFoundException, NoSuchMethodException {
            this.provider = provider;
            final Class selectorImplClass = Class.forName(name, true, null).asSubclass(Selector.class);
            final Constructor 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);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy