org.xnio.XnioWorker Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including
all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and
JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
/*
* JBoss, Home of Professional Open Source.
*
* Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual
* contributors as indicated by the @author tags.
*
* 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.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import org.jboss.threads.EnhancedQueueExecutor;
import org.wildfly.common.Assert;
import org.wildfly.common.context.ContextManager;
import org.wildfly.common.context.Contextual;
import org.wildfly.common.net.CidrAddress;
import org.wildfly.common.net.CidrAddressTable;
import org.xnio._private.Messages;
import org.xnio.channels.AcceptingChannel;
import org.xnio.channels.AssembledConnectedMessageChannel;
import org.xnio.channels.AssembledConnectedStreamChannel;
import org.xnio.channels.BoundChannel;
import org.xnio.channels.Configurable;
import org.xnio.channels.ConnectedMessageChannel;
import org.xnio.channels.ConnectedStreamChannel;
import org.xnio.channels.MulticastMessageChannel;
import org.xnio.channels.StreamChannel;
import org.xnio.channels.StreamSinkChannel;
import org.xnio.channels.StreamSourceChannel;
import org.xnio.conduits.ConduitStreamSinkChannel;
import org.xnio.conduits.ConduitStreamSourceChannel;
import org.xnio.conduits.DeflatingStreamSinkConduit;
import org.xnio.conduits.InflatingStreamSourceConduit;
import org.xnio.conduits.StreamSinkChannelWrappingConduit;
import org.xnio.conduits.StreamSourceChannelWrappingConduit;
import org.xnio.management.XnioServerMXBean;
import org.xnio.management.XnioWorkerMXBean;
import static java.lang.Math.max;
import static java.security.AccessController.doPrivileged;
import org.jboss.logging.Logger;
import static org.xnio.IoUtils.safeClose;
import static org.xnio._private.Messages.msg;
/**
* A worker for I/O channel notification.
*
* @author David M. Lloyd
*
* @since 3.0
*/
@SuppressWarnings("unused")
public abstract class XnioWorker extends AbstractExecutorService implements Configurable, ExecutorService, XnioIoFactory, Contextual {
private final Xnio xnio;
private final TaskPool taskPool;
private final String name;
private final Runnable terminationTask;
private final CidrAddressTable bindAddressTable;
private volatile int taskSeq;
private static final AtomicIntegerFieldUpdater taskSeqUpdater = AtomicIntegerFieldUpdater.newUpdater(XnioWorker.class, "taskSeq");
private static final AtomicInteger seq = new AtomicInteger(1);
private static final RuntimePermission CREATE_WORKER_PERMISSION = new RuntimePermission("createXnioWorker");
private int getNextSeq() {
return taskSeqUpdater.incrementAndGet(this);
}
private static final Logger log = Logger.getLogger("org.xnio");
/**
* Construct a new instance. Intended to be called only from implementations.
*
* @param builder the worker builder
*/
protected XnioWorker(final Builder builder) {
this.xnio = builder.xnio;
this.terminationTask = builder.terminationTask;
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(CREATE_WORKER_PERMISSION);
}
String workerName = builder.getWorkerName();
if (workerName == null) {
workerName = "XNIO-" + seq.getAndIncrement();
}
name = workerName;
final boolean markThreadAsDaemon = builder.isDaemon();
bindAddressTable = builder.getBindAddressConfigurations();
final Runnable terminationTask = new Runnable() {
public void run() {
taskPoolTerminated();
}
};
final ExecutorService executorService = builder.getExternalExecutorService();
if (executorService != null) {
if (executorService instanceof EnhancedQueueExecutor) {
taskPool = new ExternalTaskPool(
new EnhancedQueueExecutorTaskPool((EnhancedQueueExecutor) executorService));
} else if (executorService instanceof ThreadPoolExecutor) {
taskPool = new ExternalTaskPool(new ThreadPoolExecutorTaskPool((ThreadPoolExecutor) executorService));
} else {
taskPool = new ExternalTaskPool(new ExecutorServiceTaskPool(executorService));
}
} else if (EnhancedQueueExecutor.DISABLE_HINT) {
final int poolSize = max(builder.getMaxWorkerPoolSize(), builder.getCoreWorkerPoolSize());
taskPool = new ThreadPoolExecutorTaskPool(new DefaultThreadPoolExecutor(
poolSize,
poolSize,
builder.getWorkerKeepAlive(), TimeUnit.MILLISECONDS,
new LinkedBlockingDeque<>(),
new WorkerThreadFactory(builder.getThreadGroup(), builder.getWorkerStackSize(), markThreadAsDaemon),
terminationTask));
} else {
taskPool = new EnhancedQueueExecutorTaskPool(new EnhancedQueueExecutor.Builder()
.setCorePoolSize(builder.getCoreWorkerPoolSize())
.setMaximumPoolSize(builder.getMaxWorkerPoolSize())
.setKeepAliveTime(builder.getWorkerKeepAlive(), TimeUnit.MILLISECONDS)
.setThreadFactory(new WorkerThreadFactory(builder.getThreadGroup(), builder.getWorkerStackSize(), markThreadAsDaemon))
.setTerminationTask(terminationTask)
.setRegisterMBean(true)
.setMBeanName(workerName)
.build()
);
}
}
//==================================================
//
// Context methods
//
//==================================================
private static final ContextManager CONTEXT_MANAGER = doPrivileged((PrivilegedAction>) () -> new ContextManager(XnioWorker.class, "org.xnio.worker"));
static {
doPrivileged((PrivilegedAction) () -> {
CONTEXT_MANAGER.setGlobalDefaultSupplier(() -> DefaultXnioWorkerHolder.INSTANCE);
return null;
});
}
/**
* Get the context manager for XNIO workers.
*
* @return the context manager (not {@code null})
*/
public static ContextManager getContextManager() {
return CONTEXT_MANAGER;
}
/**
* Get the instance context manager for XNIO workers by delegating to {@link #getContextManager()}.
*
* @return the context manager (not {@code null})
*/
public ContextManager getInstanceContextManager() {
return getContextManager();
}
//==================================================
//
// Stream methods
//
//==================================================
// Servers
/**
* Create a stream server, for TCP or UNIX domain servers. The type of server is determined by the bind address.
*
* @param bindAddress the address to bind to
* @param acceptListener the initial accept listener
* @param optionMap the initial configuration for the server
* @return the acceptor
* @throws IOException if the server could not be created
*/
@Deprecated
public AcceptingChannel extends ConnectedStreamChannel> createStreamServer(SocketAddress bindAddress, ChannelListener super AcceptingChannel> acceptListener, OptionMap optionMap) throws IOException {
final AcceptingChannel server = createStreamConnectionServer(bindAddress, null, optionMap);
final AcceptingChannel acceptingChannel = new AcceptingChannel() {
public ConnectedStreamChannel accept() throws IOException {
final StreamConnection connection = server.accept();
return connection == null ? null : new AssembledConnectedStreamChannel(connection, connection.getSourceChannel(), connection.getSinkChannel());
}
public ChannelListener.Setter extends AcceptingChannel> getAcceptSetter() {
return ChannelListeners.getDelegatingSetter(server.getAcceptSetter(), this);
}
public ChannelListener.Setter extends AcceptingChannel> getCloseSetter() {
return ChannelListeners.getDelegatingSetter(server.getCloseSetter(), this);
}
public SocketAddress getLocalAddress() {
return server.getLocalAddress();
}
public A getLocalAddress(final Class type) {
return server.getLocalAddress(type);
}
public void suspendAccepts() {
server.suspendAccepts();
}
public void resumeAccepts() {
server.resumeAccepts();
}
public boolean isAcceptResumed() {
return server.isAcceptResumed();
}
public void wakeupAccepts() {
server.wakeupAccepts();
}
public void awaitAcceptable() throws IOException {
server.awaitAcceptable();
}
public void awaitAcceptable(final long time, final TimeUnit timeUnit) throws IOException {
server.awaitAcceptable(time, timeUnit);
}
public XnioWorker getWorker() {
return server.getWorker();
}
@Deprecated
public XnioExecutor getAcceptThread() {
return server.getAcceptThread();
}
public XnioIoThread getIoThread() {
return server.getIoThread();
}
public void close() throws IOException {
server.close();
}
public boolean isOpen() {
return server.isOpen();
}
public boolean supportsOption(final Option> option) {
return server.supportsOption(option);
}
public T getOption(final Option option) throws IOException {
return server.getOption(option);
}
public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException {
return server.setOption(option, value);
}
};
acceptingChannel.getAcceptSetter().set(acceptListener);
return acceptingChannel;
}
/**
* Create a stream server, for TCP or UNIX domain servers. The type of server is determined by the bind address.
*
* @param bindAddress the address to bind to
* @param acceptListener the initial accept listener
* @param optionMap the initial configuration for the server
* @return the acceptor
* @throws IOException if the server could not be created
*/
public AcceptingChannel createStreamConnectionServer(SocketAddress bindAddress, ChannelListener super AcceptingChannel> acceptListener, OptionMap optionMap) throws IOException {
Assert.checkNotNullParam("bindAddress", bindAddress);
if (bindAddress instanceof InetSocketAddress) {
return createTcpConnectionServer((InetSocketAddress) bindAddress, acceptListener, optionMap);
} else if (bindAddress instanceof LocalSocketAddress) {
return createLocalStreamConnectionServer((LocalSocketAddress) bindAddress, acceptListener, optionMap);
} else {
throw msg.badSockType(bindAddress.getClass());
}
}
/**
* Implementation helper method to create a TCP stream server.
*
* @param bindAddress the address to bind to
* @param acceptListener the initial accept listener
* @param optionMap the initial configuration for the server
* @return the acceptor
* @throws IOException if the server could not be created
*/
protected AcceptingChannel createTcpConnectionServer(InetSocketAddress bindAddress, ChannelListener super AcceptingChannel> acceptListener, OptionMap optionMap) throws IOException {
throw msg.unsupported("createTcpConnectionServer");
}
/**
* Implementation helper method to create a UNIX domain stream server.
*
* @param bindAddress the address to bind to
* @param acceptListener the initial accept listener
* @param optionMap the initial configuration for the server
* @return the acceptor
* @throws IOException if the server could not be created
*/
protected AcceptingChannel createLocalStreamConnectionServer(LocalSocketAddress bindAddress, ChannelListener super AcceptingChannel> acceptListener, OptionMap optionMap) throws IOException {
throw msg.unsupported("createLocalStreamConnectionServer");
}
// Connectors
/**
* Connect to a remote stream server. The protocol family is determined by the type of the socket address given.
*
* @param destination the destination address
* @param openListener the listener which will be notified when the channel is open, or {@code null} for none
* @param optionMap the option map
* @return the future result of this operation
*/
@Deprecated
public IoFuture connectStream(SocketAddress destination, ChannelListener super ConnectedStreamChannel> openListener, OptionMap optionMap) {
final FutureResult futureResult = new FutureResult();
final ChannelListener nestedOpenListener = new StreamConnectionWrapListener(futureResult, openListener);
final IoFuture future = openStreamConnection(destination, nestedOpenListener, optionMap);
future.addNotifier(STREAM_WRAPPING_HANDLER, futureResult);
futureResult.addCancelHandler(future);
return futureResult.getIoFuture();
}
/**
* Connect to a remote stream server. The protocol family is determined by the type of the socket address given.
*
* @param destination the destination address
* @param openListener the listener which will be notified when the channel is open, or {@code null} for none
* @param bindListener the listener which will be notified when the channel is bound, or {@code null} for none
* @param optionMap the option map
* @return the future result of this operation
*/
@Deprecated
public IoFuture connectStream(SocketAddress destination, ChannelListener super ConnectedStreamChannel> openListener, ChannelListener super BoundChannel> bindListener, OptionMap optionMap) {
final FutureResult futureResult = new FutureResult();
final ChannelListener nestedOpenListener = new StreamConnectionWrapListener(futureResult, openListener);
final IoFuture future = openStreamConnection(destination, nestedOpenListener, bindListener, optionMap);
future.addNotifier(STREAM_WRAPPING_HANDLER, futureResult);
futureResult.addCancelHandler(future);
return futureResult.getIoFuture();
}
/**
* Connect to a remote stream server. The protocol family is determined by the type of the socket addresses given
* (which must match).
*
* @param bindAddress the local address to bind to
* @param destination the destination address
* @param openListener the listener which will be notified when the channel is open, or {@code null} for none
* @param bindListener the listener which will be notified when the channel is bound, or {@code null} for none
* @param optionMap the option map
* @return the future result of this operation
*/
@Deprecated
public IoFuture connectStream(SocketAddress bindAddress, SocketAddress destination, ChannelListener super ConnectedStreamChannel> openListener, ChannelListener super BoundChannel> bindListener, OptionMap optionMap) {
final FutureResult futureResult = new FutureResult();
final ChannelListener nestedOpenListener = new StreamConnectionWrapListener(futureResult, openListener);
final IoFuture future = openStreamConnection(bindAddress, destination, nestedOpenListener, bindListener, optionMap);
future.addNotifier(STREAM_WRAPPING_HANDLER, futureResult);
futureResult.addCancelHandler(future);
return futureResult.getIoFuture();
}
public IoFuture openStreamConnection(SocketAddress destination, ChannelListener super StreamConnection> openListener, OptionMap optionMap) {
return chooseThread().openStreamConnection(destination, openListener, optionMap);
}
public IoFuture openStreamConnection(SocketAddress destination, ChannelListener super StreamConnection> openListener, ChannelListener super BoundChannel> bindListener, OptionMap optionMap) {
return chooseThread().openStreamConnection(destination, openListener, bindListener, optionMap);
}
public IoFuture openStreamConnection(SocketAddress bindAddress, SocketAddress destination, ChannelListener super StreamConnection> openListener, ChannelListener super BoundChannel> bindListener, OptionMap optionMap) {
return chooseThread().openStreamConnection(bindAddress, destination, openListener, bindListener, optionMap);
}
// Acceptors
/**
* Accept a stream connection at a destination address. If a wildcard address is specified, then a destination address
* is chosen in a manner specific to the OS and/or channel type.
*
* @param destination the destination (bind) address
* @param openListener the listener which will be notified when the channel is open, or {@code null} for none
* @param bindListener the listener which will be notified when the acceptor is bound, or {@code null} for none
* @param optionMap the option map
* @return the future connection
*/
@Deprecated
public IoFuture acceptStream(SocketAddress destination, ChannelListener super ConnectedStreamChannel> openListener, ChannelListener super BoundChannel> bindListener, OptionMap optionMap) {
final FutureResult futureResult = new FutureResult();
final ChannelListener nestedOpenListener = new StreamConnectionWrapListener(futureResult, openListener);
final IoFuture future = acceptStreamConnection(destination, nestedOpenListener, bindListener, optionMap);
future.addNotifier(STREAM_WRAPPING_HANDLER, futureResult);
futureResult.addCancelHandler(future);
return futureResult.getIoFuture();
}
public IoFuture acceptStreamConnection(SocketAddress destination, ChannelListener super StreamConnection> openListener, ChannelListener super BoundChannel> bindListener, OptionMap optionMap) {
return chooseThread().acceptStreamConnection(destination, openListener, bindListener, optionMap);
}
//==================================================
//
// Message (datagram) channel methods
//
//==================================================
/**
* Connect to a remote datagram server. The protocol family is determined by the type of the socket address given.
*
* @param destination the destination address
* @param openListener the listener which will be notified when the channel is open, or {@code null} for none
* @param bindListener the listener which will be notified when the channel is bound, or {@code null} for none
* @param optionMap the option map
* @return the future result of this operation
*/
@Deprecated
// FIXME XNIO-192 invoke bind listener
public IoFuture connectDatagram(SocketAddress destination, ChannelListener super ConnectedMessageChannel> openListener, ChannelListener super BoundChannel> bindListener, OptionMap optionMap) {
final FutureResult futureResult = new FutureResult();
final ChannelListener nestedOpenListener = new MessageConnectionWrapListener(futureResult, openListener);
final IoFuture future = openMessageConnection(destination, nestedOpenListener, optionMap);
future.addNotifier(MESSAGE_WRAPPING_HANDLER, futureResult);
futureResult.addCancelHandler(future);
return futureResult.getIoFuture();
}
/**
* Connect to a remote datagram server. The protocol family is determined by the type of the socket addresses given
* (which must match).
*
* @param bindAddress the local address to bind to
* @param destination the destination address
* @param openListener the listener which will be notified when the channel is open, or {@code null} for none
* @param bindListener the listener which will be notified when the channel is bound, or {@code null} for none
* @param optionMap the option map
* @return the future result of this operation
*/
@Deprecated
// FIXME bindAddress is now ignored
public IoFuture connectDatagram(SocketAddress bindAddress, SocketAddress destination, ChannelListener super ConnectedMessageChannel> openListener, ChannelListener super BoundChannel> bindListener, OptionMap optionMap) {
final FutureResult futureResult = new FutureResult();
final ChannelListener nestedOpenListener = new MessageConnectionWrapListener(futureResult, openListener);
final IoFuture future = openMessageConnection(destination, nestedOpenListener, optionMap);
future.addNotifier(MESSAGE_WRAPPING_HANDLER, futureResult);
futureResult.addCancelHandler(future);
return futureResult.getIoFuture();
}
public IoFuture openMessageConnection(final SocketAddress destination, final ChannelListener super MessageConnection> openListener, final OptionMap optionMap) {
return chooseThread().openMessageConnection(destination, openListener, optionMap);
}
// Acceptors
/**
* Accept a message connection at a destination address. If a wildcard address is specified, then a destination address
* is chosen in a manner specific to the OS and/or channel type.
*
* @param destination the destination (bind) address
* @param openListener the listener which will be notified when the channel is open, or {@code null} for none
* @param bindListener the listener which will be notified when the acceptor is bound, or {@code null} for none
* @param optionMap the option map
* @return the future connection
*/
@Deprecated
public IoFuture acceptDatagram(SocketAddress destination, ChannelListener super ConnectedMessageChannel> openListener, ChannelListener super BoundChannel> bindListener, OptionMap optionMap) {
final FutureResult futureResult = new FutureResult();
final ChannelListener nestedOpenListener = new MessageConnectionWrapListener(futureResult, openListener);
final IoFuture future = acceptMessageConnection(destination, nestedOpenListener, bindListener, optionMap);
future.addNotifier(MESSAGE_WRAPPING_HANDLER, futureResult);
futureResult.addCancelHandler(future);
return futureResult.getIoFuture();
}
public IoFuture acceptMessageConnection(final SocketAddress destination, final ChannelListener super MessageConnection> openListener, final ChannelListener super BoundChannel> bindListener, final OptionMap optionMap) {
return chooseThread().acceptMessageConnection(destination, openListener, bindListener, optionMap);
}
//==================================================
//
// UDP methods
//
//==================================================
/**
* Create a UDP server. The UDP server can be configured to be multicast-capable; this should only be
* done if multicast is needed, since some providers have a performance penalty associated with multicast.
* The provider's default executor will be used to execute listener methods.
*
* @param bindAddress the bind address
* @param bindListener the initial open-connection listener
* @param optionMap the initial configuration for the server
* @return the UDP server channel
* @throws java.io.IOException if the server could not be created
*
* @since 3.0
*/
public MulticastMessageChannel createUdpServer(InetSocketAddress bindAddress, ChannelListener super MulticastMessageChannel> bindListener, OptionMap optionMap) throws IOException {
throw msg.unsupported("createUdpServer");
}
/**
* Create a UDP server. The UDP server can be configured to be multicast-capable; this should only be
* done if multicast is needed, since some providers have a performance penalty associated with multicast.
* The provider's default executor will be used to execute listener methods.
*
* @param bindAddress the bind address
* @param optionMap the initial configuration for the server
* @return the UDP server channel
* @throws java.io.IOException if the server could not be created
*
* @since 3.0
*/
public MulticastMessageChannel createUdpServer(InetSocketAddress bindAddress, OptionMap optionMap) throws IOException {
return createUdpServer(bindAddress, ChannelListeners.nullChannelListener(), optionMap);
}
//==================================================
//
// Stream pipe methods
//
//==================================================
/**
* Open a bidirectional stream pipe.
*
* @param leftOpenListener the left-hand open listener
* @param rightOpenListener the right-hand open listener
* @param optionMap the pipe channel configuration
* @throws java.io.IOException if the pipe could not be created
* @deprecated Users should prefer the simpler {@link #createFullDuplexPipe()} instead.
*/
@Deprecated
public void createPipe(ChannelListener super StreamChannel> leftOpenListener, ChannelListener super StreamChannel> rightOpenListener, final OptionMap optionMap) throws IOException {
final ChannelPipe pipe = createFullDuplexPipe();
final boolean establishWriting = optionMap.get(Options.WORKER_ESTABLISH_WRITING, false);
final StreamChannel left = pipe.getLeftSide();
XnioExecutor leftExec = establishWriting ? left.getWriteThread() : left.getReadThread();
final StreamChannel right = pipe.getRightSide();
XnioExecutor rightExec = establishWriting ? right.getWriteThread() : right.getReadThread();
// not unsafe - http://youtrack.jetbrains.net/issue/IDEA-59290
//noinspection unchecked
leftExec.execute(ChannelListeners.getChannelListenerTask(left, leftOpenListener));
// not unsafe - http://youtrack.jetbrains.net/issue/IDEA-59290
//noinspection unchecked
rightExec.execute(ChannelListeners.getChannelListenerTask(right, rightOpenListener));
}
/**
* Open a unidirectional stream pipe.
*
* @param sourceListener the source open listener
* @param sinkListener the sink open listener
* @param optionMap the pipe channel configuration
* @throws java.io.IOException if the pipe could not be created
* @deprecated Users should prefer the simpler {@link #createHalfDuplexPipe()} instead.
*/
@Deprecated
public void createOneWayPipe(ChannelListener super StreamSourceChannel> sourceListener, ChannelListener super StreamSinkChannel> sinkListener, final OptionMap optionMap) throws IOException {
final ChannelPipe pipe = createHalfDuplexPipe();
final StreamSourceChannel left = pipe.getLeftSide();
XnioExecutor leftExec = left.getReadThread();
final StreamSinkChannel right = pipe.getRightSide();
XnioExecutor rightExec = right.getWriteThread();
// not unsafe - http://youtrack.jetbrains.net/issue/IDEA-59290
//noinspection unchecked
leftExec.execute(ChannelListeners.getChannelListenerTask(left, sourceListener));
// not unsafe - http://youtrack.jetbrains.net/issue/IDEA-59290
//noinspection unchecked
rightExec.execute(ChannelListeners.getChannelListenerTask(right, sinkListener));
}
//==================================================
//
// Compression methods
//
//==================================================
/**
* Create a stream channel that decompresses the source data according to the configuration in the given option map.
*
* @param delegate the compressed channel
* @param options the configuration options for the channel
* @return a decompressed channel
* @throws IOException if the channel could not be constructed
*/
public StreamSourceChannel getInflatingChannel(final StreamSourceChannel delegate, OptionMap options) throws IOException {
final boolean nowrap;
switch (options.get(Options.COMPRESSION_TYPE, CompressionType.DEFLATE)) {
case DEFLATE: nowrap = false; break;
case GZIP: nowrap = true; break;
default: throw msg.badCompressionFormat();
}
return getInflatingChannel(delegate, new Inflater(nowrap));
}
/**
* Create a stream channel that decompresses the source data according to the configuration in the given inflater.
*
* @param delegate the compressed channel
* @param inflater the inflater to use
* @return a decompressed channel
* @throws IOException if the channel could not be constructed
*/
protected StreamSourceChannel getInflatingChannel(final StreamSourceChannel delegate, final Inflater inflater) throws IOException {
return new ConduitStreamSourceChannel(Configurable.EMPTY, new InflatingStreamSourceConduit(new StreamSourceChannelWrappingConduit(delegate), inflater));
}
/**
* Create a stream channel that compresses to the destination according to the configuration in the given option map.
*
* @param delegate the channel to compress to
* @param options the configuration options for the channel
* @return a compressed channel
* @throws IOException if the channel could not be constructed
*/
public StreamSinkChannel getDeflatingChannel(final StreamSinkChannel delegate, final OptionMap options) throws IOException {
final int level = options.get(Options.COMPRESSION_LEVEL, -1);
final boolean nowrap;
switch (options.get(Options.COMPRESSION_TYPE, CompressionType.DEFLATE)) {
case DEFLATE: nowrap = false; break;
case GZIP: nowrap = true; break;
default: throw msg.badCompressionFormat();
}
return getDeflatingChannel(delegate, new Deflater(level, nowrap));
}
/**
* Create a stream channel that compresses to the destination according to the configuration in the given inflater.
*
* @param delegate the channel to compress to
* @param deflater the deflater to use
* @return a compressed channel
* @throws IOException if the channel could not be constructed
*/
protected StreamSinkChannel getDeflatingChannel(final StreamSinkChannel delegate, final Deflater deflater) throws IOException {
return new ConduitStreamSinkChannel(Configurable.EMPTY, new DeflatingStreamSinkConduit(new StreamSinkChannelWrappingConduit(delegate), deflater));
}
public ChannelPipe createFullDuplexPipe() throws IOException {
return chooseThread().createFullDuplexPipe();
}
public ChannelPipe createFullDuplexPipeConnection() throws IOException {
return chooseThread().createFullDuplexPipeConnection();
}
public ChannelPipe createHalfDuplexPipe() throws IOException {
return chooseThread().createHalfDuplexPipe();
}
public ChannelPipe createFullDuplexPipeConnection(final XnioIoFactory peer) throws IOException {
return chooseThread().createFullDuplexPipeConnection(peer);
}
public ChannelPipe createHalfDuplexPipe(final XnioIoFactory peer) throws IOException {
return chooseThread().createHalfDuplexPipe(peer);
}
//==================================================
//
// State methods
//
//==================================================
/**
* Shut down this worker. This method returns immediately. Upon return worker shutdown will have
* commenced but not necessarily completed. When worker shutdown is complete, the termination task (if one was
* defined) will be executed.
*/
public abstract void shutdown();
/**
* Immediately terminate the worker. Any outstanding tasks are collected and returned in a list. Upon return
* worker shutdown will have commenced but not necessarily completed; however the worker will only complete its
* current tasks instead of completing all tasks.
*
* @return the list of outstanding tasks
*/
public abstract List shutdownNow();
/**
* Determine whether the worker has been shut down. Will return {@code true} once either shutdown method has
* been called.
*
* @return {@code true} the worker has been shut down
*/
public abstract boolean isShutdown();
/**
* Determine whether the worker has terminated. Will return {@code true} once all worker threads are exited
* (with the possible exception of the thread running the termination task, if any).
*
* @return {@code true} if the worker is terminated
*/
public abstract boolean isTerminated();
/**
* Wait for termination.
*
* @param timeout the amount of time to wait
* @param unit the unit of time
* @return {@code true} if termination completed before the timeout expired
* @throws InterruptedException if the operation was interrupted
*/
public abstract boolean awaitTermination(final long timeout, final TimeUnit unit) throws InterruptedException;
/**
* Wait for termination.
*
* @throws InterruptedException if the operation was interrupted
*/
public abstract void awaitTermination() throws InterruptedException;
//==================================================
//
// Thread pool methods
//
//==================================================
/**
* Get an I/O thread from this worker. The thread may be chosen based on arbitrary rules.
*
* @return the I/O thread
*/
public final XnioIoThread getIoThread() {
return chooseThread();
}
/**
* Get an I/O thread from this worker. The thread is chosen based on the given hash code.
*
* @param hashCode the hash code
* @return the thread
*/
public abstract XnioIoThread getIoThread(int hashCode);
/**
* Get the user task to run once termination is complete.
*
* @return the termination task
*/
protected Runnable getTerminationTask() {
return terminationTask;
}
/**
* Callback to indicate that the task thread pool has terminated. Not called if the task pool is external.
*/
protected void taskPoolTerminated() {}
/**
* Initiate shutdown of the task thread pool. When all the tasks and threads have completed,
* the {@link #taskPoolTerminated()} method is called.
*/
protected void shutDownTaskPool() {
if (isTaskPoolExternal()) {
taskPoolTerminated();
} else {
doPrivileged(new PrivilegedAction