org.xnio.Xnio Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xnio-api Show documentation
Show all versions of xnio-api Show documentation
The API JAR of the XNIO project
/*
* 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
*/
@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 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() {
public MBeanServer run() {
return ManagementFactory.getPlatformMBeanServer();
}
});
}
}
/**
* 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 map = new EnumMap(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.
*/
private final String 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 BLOCKING = new ThreadLocal() {
protected Boolean initialValue() {
return Boolean.TRUE;
}
};
/**
* 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 threadLocal = BLOCKING;
try {
return threadLocal.get().booleanValue();
} finally {
threadLocal.set(Boolean.valueOf(newSetting));
}
}
/**
* 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
*/
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.
*
* @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>() {
public ServiceLoader 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.
*
* @return the XNIO provider instance
*
* @since 3.0
*/
public static Xnio getInstance() {
return doGetInstance(null, doPrivileged(new PrivilegedAction>() {
public ServiceLoader run() {
return ServiceLoader.load(XnioProvider.class, Xnio.class.getClassLoader());
}
}));
}
/**
* 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>() {
public ServiceLoader run() {
return ServiceLoader.load(XnioProvider.class, classLoader);
}
}));
}
/**
* 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>() {
public ServiceLoader run() {
return ServiceLoader.load(XnioProvider.class, Xnio.class.getClassLoader());
}
}));
}
private static synchronized Xnio doGetInstance(final String provider, final ServiceLoader serviceLoader) {
final Iterator 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 sr = context.getServiceReference(Xnio.class);
if (sr == null) {
return null;
}
return context.getService(sr);
}
}
//==================================================
//
// SSL methods
//
//==================================================
/**
* 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.
*
* @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.
*
* @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 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.
*
* @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.
*
* @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.
*
* @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.
*
* @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.
*
* @return the worker builder (not {@code null})
*/
public XnioWorker.Builder createWorkerBuilder() {
return new XnioWorker.Builder(this);
}
/**
* 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.
*
* @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.
*
* @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.
*
* @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.
*
* @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);
}
/**
* Implement tasks that will be executed on thread exits if a task worker
* thread is initialized through {@code XnioWorker$WorkerThreadFactory}.
*/
protected void handleThreadExit() {}
//==================================================
//
// General methods
//
//==================================================
/**
* Get the name of this XNIO provider.
*
* @return the name
*/
public final String getName() {
return name;
}
/**
* 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 {@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 {@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.
*
* @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.
*
* @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.
*
* @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) {
}
}
}
}