/*
 * JBoss, Home of Professional Open Source
 *
 * Copyright 2008 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;

import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.security.AccessController;
import java.security.GeneralSecurityException;
import java.security.PrivilegedAction;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.xnio.management.XnioProviderMXBean;
import org.xnio.management.XnioServerMXBean;
import org.xnio.management.XnioWorkerMXBean;
import org.xnio.ssl.JsseSslUtils;
import org.xnio.ssl.JsseXnioSsl;
import org.xnio.ssl.XnioSsl;

import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;

import static java.security.AccessController.doPrivileged;
import static org.xnio._private.Messages.msg;

The XNIO provider class.
@apiviz.landmark
/** * The XNIO provider class. * * @apiviz.landmark */
@SuppressWarnings("unused") public abstract class Xnio { static final InetSocketAddress ANY_INET_ADDRESS = new InetSocketAddress(0); static final LocalSocketAddress ANY_LOCAL_ADDRESS = new LocalSocketAddress(""); private static final EnumMap<FileAccess, OptionMap> FILE_ACCESS_OPTION_MAPS; private static final RuntimePermission ALLOW_BLOCKING_SETTING = new RuntimePermission("changeThreadBlockingSetting"); static final class MBeanHolder { private static final MBeanServer MBEAN_SERVER; static { MBEAN_SERVER = doPrivileged(new PrivilegedAction<MBeanServer>() { public MBeanServer run() { return ManagementFactory.getPlatformMBeanServer(); } }); } }
A flag indicating the presence of NIO.2 (JDK 7). Always true as of XNIO version 3.5.0, which requires Java 8.
/** * A flag indicating the presence of NIO.2 (JDK 7). Always {@code true} as of XNIO version 3.5.0, which requires * Java 8. */
public static final boolean NIO2 = true; static { msg.greeting(Version.VERSION); final EnumMap<FileAccess, OptionMap> map = new EnumMap<FileAccess, OptionMap>(FileAccess.class); for (FileAccess access : FileAccess.values()) { map.put(access, OptionMap.create(Options.FILE_ACCESS, access)); } FILE_ACCESS_OPTION_MAPS = map; }
The name of this provider instance.
/** * The name of this provider instance. */
private final String name;
Construct an XNIO provider instance. Used by implementors only. To get an XNIO instance, use one of the getInstance() methods.
Params:
  • name – the provider name
/** * Construct an XNIO provider instance. Used by implementors only. To get an XNIO instance, * use one of the {@link org.xnio.Xnio#getInstance()} methods. * * @param name the provider name */
protected Xnio(String name) { if (name == null) { throw msg.nullParameter("name"); } this.name = name; } private static final ThreadLocal<Boolean> BLOCKING = new ThreadLocal<Boolean>() { protected Boolean initialValue() { return Boolean.TRUE; } };
Allow (or disallow) blocking I/O on the current thread. Requires the changeThreadBlockingSetting RuntimePermission.
Params:
  • newSetting – true to allow blocking I/O, false to disallow it
Throws:
  • SecurityException – if a security manager is present and disallows changing the changeThreadBlockingSetting RuntimePermission
Returns:the previous setting
/** * Allow (or disallow) blocking I/O on the current thread. Requires the {@code changeThreadBlockingSetting} * {@link RuntimePermission}. * * @param newSetting {@code true} to allow blocking I/O, {@code false} to disallow it * @return the previous setting * @throws SecurityException if a security manager is present and disallows changing the {@code changeThreadBlockingSetting} {@code RuntimePermission} */
public static boolean allowBlocking(boolean newSetting) throws SecurityException { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(ALLOW_BLOCKING_SETTING); } final ThreadLocal<Boolean> threadLocal = BLOCKING; try { return threadLocal.get().booleanValue(); } finally { threadLocal.set(Boolean.valueOf(newSetting)); } }
Determine whether blocking I/O is allowed from the current thread.
Returns:true if blocking I/O is allowed, false otherwise
/** * Determine whether blocking I/O is allowed from the current thread. * * @return {@code true} if blocking I/O is allowed, {@code false} otherwise */
public static boolean isBlockingAllowed() { return BLOCKING.get().booleanValue(); }
Perform a check for whether blocking is allowed on the current thread.
Throws:
  • IllegalStateException – if blocking is not allowed on the current thread
/** * Perform a check for whether blocking is allowed on the current thread. * * @throws IllegalStateException if blocking is not allowed on the current thread */
public static void checkBlockingAllowed() throws IllegalStateException { if (! BLOCKING.get().booleanValue()) { throw msg.blockingNotAllowed(); } }
Get an XNIO provider instance. If multiple providers are available, use the first one encountered.
Params:
  • classLoader – the class loader to search in
Returns:the XNIO provider instance
Since:3.0
/** * Get an XNIO provider instance. If multiple providers are * available, use the first one encountered. * * @param classLoader the class loader to search in * @return the XNIO provider instance * * @since 3.0 */
public static Xnio getInstance(final ClassLoader classLoader) { return doGetInstance(null, doPrivileged(new PrivilegedAction<ServiceLoader<XnioProvider>>() { public ServiceLoader<XnioProvider> run() { return ServiceLoader.load(XnioProvider.class, classLoader); } })); }
Get an XNIO provider instance from XNIO's class loader. If multiple providers are available, use the first one encountered.
Returns:the XNIO provider instance
Since:3.0
/** * Get an XNIO provider instance from XNIO's class loader. If multiple providers are * available, use the first one encountered. * * @return the XNIO provider instance * * @since 3.0 */
public static Xnio getInstance() { return doGetInstance(null, doPrivileged(new PrivilegedAction<ServiceLoader<XnioProvider>>() { public ServiceLoader<XnioProvider> run() { return ServiceLoader.load(XnioProvider.class, Xnio.class.getClassLoader()); } })); }
Get a specific XNIO provider instance.
Params:
  • provider – the provider name, or null for the first available
  • classLoader – the class loader to search in
Returns:the XNIO provider instance
Since:3.0
/** * Get a specific XNIO provider instance. * * @param provider the provider name, or {@code null} for the first available * @param classLoader the class loader to search in * @return the XNIO provider instance * * @since 3.0 */
public static Xnio getInstance(String provider, final ClassLoader classLoader) { return doGetInstance(provider, doPrivileged(new PrivilegedAction<ServiceLoader<XnioProvider>>() { public ServiceLoader<XnioProvider> run() { return ServiceLoader.load(XnioProvider.class, classLoader); } })); }
Get a specific XNIO provider instance from XNIO's class loader.
Params:
  • provider – the provider name, or null for the first available
Returns:the XNIO provider instance
Since:3.0
/** * Get a specific XNIO provider instance from XNIO's class loader. * * @param provider the provider name, or {@code null} for the first available * @return the XNIO provider instance * * @since 3.0 */
public static Xnio getInstance(String provider) { return doGetInstance(provider, doPrivileged(new PrivilegedAction<ServiceLoader<XnioProvider>>() { public ServiceLoader<XnioProvider> run() { return ServiceLoader.load(XnioProvider.class, Xnio.class.getClassLoader()); } })); } private static synchronized Xnio doGetInstance(final String provider, final ServiceLoader<XnioProvider> serviceLoader) { final Iterator<XnioProvider> iterator = serviceLoader.iterator(); for (;;) { try { if (! iterator.hasNext()) break; final XnioProvider xnioProvider = iterator.next(); try { if (provider == null || provider.equals(xnioProvider.getName())) { return xnioProvider.getInstance(); } } catch (Throwable t) { msg.debugf(t, "Not loading provider %s", xnioProvider.getName()); } } catch (Throwable t) { msg.debugf(t, "Skipping non-loadable provider"); } } try { Xnio xnio = OsgiSupport.doGetOsgiService(); if (xnio != null) { return xnio; } } catch (NoClassDefFoundError t) { // Ignore } catch (Throwable t) { msg.debugf(t, "Not using OSGi service"); } throw msg.noProviderFound(); } static class OsgiSupport { static Xnio doGetOsgiService() { Bundle bundle = FrameworkUtil.getBundle(Xnio.class); BundleContext context = bundle.getBundleContext(); if (context == null) { throw new IllegalStateException("Bundle not started"); } ServiceReference<Xnio> sr = context.getServiceReference(Xnio.class); if (sr == null) { return null; } return context.getService(sr); } } //================================================== // // SSL methods // //==================================================
Get an SSL provider for this XNIO provider.
Params:
  • optionMap – the option map to use for configuring SSL
Throws:
Returns:the SSL provider
/** * Get an SSL provider for this XNIO provider. * * @param optionMap the option map to use for configuring SSL * @return the SSL provider * @throws GeneralSecurityException if an exception occurred configuring the SSL provider */
public XnioSsl getSslProvider(final OptionMap optionMap) throws GeneralSecurityException { return new JsseXnioSsl(this, optionMap); }
Get an SSL provider for this XNIO provider.
Params:
  • optionMap – the option map to use for configuring SSL
  • keyManagers – the key managers to use, or null to configure from the option map
  • trustManagers – the trust managers to use, or null to configure from the option map
Throws:
Returns:the SSL provider
/** * Get an SSL provider for this XNIO provider. * * @param optionMap the option map to use for configuring SSL * @param keyManagers the key managers to use, or {@code null} to configure from the option map * @param trustManagers the trust managers to use, or {@code null} to configure from the option map * @return the SSL provider * @throws GeneralSecurityException if an exception occurred configuring the SSL provider */
public XnioSsl getSslProvider(final KeyManager[] keyManagers, final TrustManager[] trustManagers, final OptionMap optionMap) throws GeneralSecurityException { return new JsseXnioSsl(this, optionMap, JsseSslUtils.createSSLContext(keyManagers, trustManagers, null, optionMap)); } //================================================== // // File system methods // //==================================================
Open a file on the filesystem.
Params:
  • file – the file to open
  • options – the file-open options
Throws:
Returns:the file channel
/** * Open a file on the filesystem. * * @param file the file to open * @param options the file-open options * @return the file channel * @throws IOException if an I/O error occurs */
public FileChannel openFile(File file, OptionMap options) throws IOException { if (file == null) { throw msg.nullParameter("file"); } if (options == null) { throw msg.nullParameter("options"); } try { final FileAccess fileAccess = options.get(Options.FILE_ACCESS, FileAccess.READ_WRITE); final boolean append = options.get(Options.FILE_APPEND, false); final boolean create = options.get(Options.FILE_CREATE, fileAccess != FileAccess.READ_ONLY); final EnumSet<StandardOpenOption> openOptions = EnumSet.noneOf(StandardOpenOption.class); if (create) { openOptions.add(StandardOpenOption.CREATE); } if (fileAccess.isRead()) { openOptions.add(StandardOpenOption.READ); } if (fileAccess.isWrite()) { openOptions.add(StandardOpenOption.WRITE); } if (append) { openOptions.add(StandardOpenOption.APPEND); } final Path path = file.toPath(); return new XnioFileChannel(path.getFileSystem().provider().newFileChannel(path, openOptions)); } catch (NoSuchFileException e) { throw new FileNotFoundException(e.getMessage()); } }
Open a file on the filesystem.
Params:
  • fileName – the file name of the file to open
  • options – the file-open options
Throws:
Returns:the file channel
/** * Open a file on the filesystem. * * @param fileName the file name of the file to open * @param options the file-open options * @return the file channel * @throws IOException if an I/O error occurs */
public FileChannel openFile(String fileName, OptionMap options) throws IOException { if (fileName == null) { throw msg.nullParameter("fileName"); } return openFile(new File(fileName), options); }
Open a file on the filesystem.
Params:
  • file – the file to open
  • access – the file access level to use
Throws:
Returns:the file channel
/** * Open a file on the filesystem. * * @param file the file to open * @param access the file access level to use * @return the file channel * @throws IOException if an I/O error occurs */
public FileChannel openFile(File file, FileAccess access) throws IOException { if (access == null) { throw msg.nullParameter("access"); } return openFile(file, FILE_ACCESS_OPTION_MAPS.get(access)); }
Open a file on the filesystem.
Params:
  • fileName – the file name of the file to open
  • access – the file access level to use
Throws:
Returns:the file channel
/** * Open a file on the filesystem. * * @param fileName the file name of the file to open * @param access the file access level to use * @return the file channel * @throws IOException if an I/O error occurs */
public FileChannel openFile(String fileName, FileAccess access) throws IOException { if (access == null) { throw msg.nullParameter("access"); } if (fileName == null) { throw msg.nullParameter("fileName"); } return openFile(new File(fileName), FILE_ACCESS_OPTION_MAPS.get(access)); }
Unwrap an XNIO-wrapped file channel. For use by providers.
Params:
  • src – the possibly wrapped file channel
Returns:the unwrapped file channel
/** * Unwrap an XNIO-wrapped file channel. For use by providers. * * @param src the possibly wrapped file channel * @return the unwrapped file channel */
protected FileChannel unwrapFileChannel(FileChannel src) { if (src instanceof XnioFileChannel) { return ((XnioFileChannel)src).getDelegate(); } else { return src; } } //================================================== // // Worker methods // //==================================================
Create a new worker builder.
Returns:the worker builder (not null)
/** * Create a new worker builder. * * @return the worker builder (not {@code null}) */
public XnioWorker.Builder createWorkerBuilder() { return new XnioWorker.Builder(this); }
Construct an XNIO worker from a builder.
Params:
  • builder – the builder (must not be null)
Returns:the constructed worker
/** * Construct an XNIO worker from a builder. * * @param builder the builder (must not be {@code null}) * @return the constructed worker */
protected abstract XnioWorker build(XnioWorker.Builder builder);
Construct a new XNIO worker.
Params:
  • optionMap – the options to use to configure the worker
Throws:
Returns:the new worker
/** * Construct a new XNIO worker. * * @param optionMap the options to use to configure the worker * @return the new worker * @throws IOException if the worker failed to be opened * @throws IllegalArgumentException if an option value is invalid for this worker */
public XnioWorker createWorker(OptionMap optionMap) throws IOException, IllegalArgumentException { return createWorker(null, optionMap); }
Construct a new XNIO worker.
Params:
  • threadGroup – the thread group for worker threads
  • optionMap – the options to use to configure the worker
Throws:
Returns:the new worker
/** * Construct a new XNIO worker. * * @param threadGroup the thread group for worker threads * @param optionMap the options to use to configure the worker * @return the new worker * @throws IOException if the worker failed to be opened * @throws IllegalArgumentException if an option value is invalid for this worker */
public XnioWorker createWorker(ThreadGroup threadGroup, OptionMap optionMap) throws IOException, IllegalArgumentException { return createWorker(threadGroup, optionMap, null); }
Construct a new XNIO worker.
Params:
  • threadGroup – the thread group for worker threads
  • optionMap – the options to use to configure the worker
  • terminationTask – the task to run after the worker has shut down
Throws:
Returns:the new worker
/** * Construct a new XNIO worker. * * @param threadGroup the thread group for worker threads * @param optionMap the options to use to configure the worker * @param terminationTask the task to run after the worker has shut down * @return the new worker * @throws IOException if the worker failed to be opened * @throws IllegalArgumentException if an option value is invalid for this worker */
public XnioWorker createWorker(ThreadGroup threadGroup, OptionMap optionMap, Runnable terminationTask) throws IOException, IllegalArgumentException { final XnioWorker.Builder workerBuilder = createWorkerBuilder(); workerBuilder.populateFromOptions(optionMap); workerBuilder.setThreadGroup(threadGroup); workerBuilder.setTerminationTask(terminationTask); return workerBuilder.build(); }
Creates a file system watcher, that can be used to monitor file system changes.
Params:
  • name – The watcher name
  • options – The options to use to create the watcher
Returns:The file system watcher
/** * Creates a file system watcher, that can be used to monitor file system changes. * * @param name The watcher name * @param options The options to use to create the watcher * @return The file system watcher */
public FileSystemWatcher createFileSystemWatcher(final String name, final OptionMap options) { int pollInterval = options.get(Options.WATCHER_POLL_INTERVAL, 5000); boolean daemonThread = options.get(Options.THREAD_DAEMON, true); return new PollingFileSystemWatcher(name, pollInterval, daemonThread); } //================================================== // // General methods // //==================================================
Get the name of this XNIO provider.
Returns:the name
/** * Get the name of this XNIO provider. * * @return the name */
public final String getName() { return name; }
Get a string representation of this XNIO provider.
Returns:the string representation
/** * Get a string representation of this XNIO provider. * * @return the string representation */
public final String toString() { return String.format("XNIO provider \"%s\" <%s@%s>", getName(), getClass().getName(), Integer.toHexString(hashCode())); }
Get an XNIO property. The property name must start with "xnio.".
Params:
  • name – the property name
Returns:the property value, or null if it wasn't found
Since:1.2
/** * Get an XNIO property. The property name must start with {@code "xnio."}. * * @param name the property name * @return the property value, or {@code null} if it wasn't found * @since 1.2 */
protected static String getProperty(final String name) { if (! name.startsWith("xnio.")) { throw msg.propReadForbidden(); } final SecurityManager sm = System.getSecurityManager(); if (sm != null) { return AccessController.doPrivileged(new ReadPropertyAction(name, null)); } else { return System.getProperty(name); } }
Get an XNIO property. The property name must start with "xnio.".
Params:
  • name – the property name
  • defaultValue – the default value
Returns:the property value, or defaultValue if it wasn't found
Since:1.2
/** * Get an XNIO property. The property name must start with {@code "xnio."}. * * @param name the property name * @param defaultValue the default value * @return the property value, or {@code defaultValue} if it wasn't found * @since 1.2 */
protected static String getProperty(final String name, final String defaultValue) { if (! name.startsWith("xnio.")) { throw msg.propReadForbidden(); } final SecurityManager sm = System.getSecurityManager(); if (sm != null) { return AccessController.doPrivileged(new ReadPropertyAction(name, defaultValue)); } else { return System.getProperty(name, defaultValue); } }
Register an MBean. If the MBean cannot be registered, this method will simply return.
Params:
  • providerMXBean – the provider MBean to register
Returns:a handle which may be used to remove the registration
/** * Register an MBean. If the MBean cannot be registered, this method will simply return. * * @param providerMXBean the provider MBean to register * @return a handle which may be used to remove the registration */
protected static Closeable register(XnioProviderMXBean providerMXBean) { try { final ObjectName objectName = new ObjectName("org.xnio", ObjectProperties.properties(ObjectProperties.property("type", "Xnio"), ObjectProperties.property("provider", ObjectName.quote(providerMXBean.getName())))); MBeanHolder.MBEAN_SERVER.registerMBean(providerMXBean, objectName); return new MBeanCloseable(objectName); } catch (Throwable ignored) { return IoUtils.nullCloseable(); } }
Register an MBean. If the MBean cannot be registered, this method will simply return.
Params:
  • workerMXBean – the worker MBean to register
Returns:a handle which may be used to remove the registration
/** * Register an MBean. If the MBean cannot be registered, this method will simply return. * * @param workerMXBean the worker MBean to register * @return a handle which may be used to remove the registration */
protected static Closeable register(XnioWorkerMXBean workerMXBean) { try { final ObjectName objectName = new ObjectName("org.xnio", ObjectProperties.properties(ObjectProperties.property("type", "Xnio"), ObjectProperties.property("provider", ObjectName.quote(workerMXBean.getProviderName())), ObjectProperties.property("worker", ObjectName.quote(workerMXBean.getName())))); MBeanHolder.MBEAN_SERVER.registerMBean(workerMXBean, objectName); return new MBeanCloseable(objectName); } catch (Throwable ignored) { return IoUtils.nullCloseable(); } }
Register an MBean. If the MBean cannot be registered, this method will simply return.
Params:
  • serverMXBean – the server MBean to register
Returns:a handle which may be used to remove the registration
/** * Register an MBean. If the MBean cannot be registered, this method will simply return. * * @param serverMXBean the server MBean to register * @return a handle which may be used to remove the registration */
protected static Closeable register(XnioServerMXBean serverMXBean) { try { final ObjectName objectName = new ObjectName("org.xnio", ObjectProperties.properties(ObjectProperties.property("type", "Xnio"), ObjectProperties.property("provider", ObjectName.quote(serverMXBean.getProviderName())), ObjectProperties.property("worker", ObjectName.quote(serverMXBean.getWorkerName())), ObjectProperties.property("address", ObjectName.quote(serverMXBean.getBindAddress())))); MBeanHolder.MBEAN_SERVER.registerMBean(serverMXBean, objectName); return new MBeanCloseable(objectName); } catch (Throwable ignored) { return IoUtils.nullCloseable(); } } static class MBeanCloseable extends AtomicBoolean implements Closeable { private final ObjectName objectName; MBeanCloseable(final ObjectName objectName) { this.objectName = objectName; } public void close() { if (! getAndSet(true)) try { MBeanHolder.MBEAN_SERVER.unregisterMBean(objectName); } catch (Throwable ignored) { } } } }