() {
public void handleEvent(final T channel) {
try {
executor.execute(getChannelListenerTask(channel, listener));
} catch (RejectedExecutionException e) {
listenerMsg.executorSubmitFailed(e, channel);
IoUtils.safeClose(channel);
}
}
public String toString() {
return "Executor channel listener -> " + listener;
}
};
}
/**
* A flushing channel listener. Flushes the channel and then calls the delegate listener. Calls the exception
* handler if an exception occurs. The delegate listener should ensure that the channel write listener is appropriately set.
*
* The returned listener is stateless and may be reused on any number of channels concurrently or sequentially.
*
* @param delegate the delegate listener
* @param exceptionHandler the exception handler
* @param the channel type
* @return the flushing channel listener
*/
public static ChannelListener flushingChannelListener(final ChannelListener super T> delegate, final ChannelExceptionHandler super T> exceptionHandler) {
return new ChannelListener() {
public void handleEvent(final T channel) {
final boolean result;
try {
result = channel.flush();
} catch (IOException e) {
channel.suspendWrites();
invokeChannelExceptionHandler(channel, exceptionHandler, e);
return;
}
if (result) {
Channels.setWriteListener(channel, delegate);
invokeChannelListener(channel, delegate);
} else {
Channels.setWriteListener(channel, this);
channel.resumeWrites();
}
}
public String toString() {
return "Flushing channel listener -> " + delegate;
}
};
}
/**
* A write shutdown channel listener. Shuts down and flushes the channel and calls the delegate listener. Calls
* the exception handler if an exception occurs. When the delegate listener is called, the channel's write side will be shut down and flushed.
* The delegate listener should ensure that the channel write listener is appropriately set.
*
* @param delegate the delegate listener
* @param exceptionHandler the exception handler
* @param the channel type
* @return the channel listener
*/
public static ChannelListener writeShutdownChannelListener(final ChannelListener super T> delegate, final ChannelExceptionHandler super T> exceptionHandler) {
final ChannelListener flushingListener = flushingChannelListener(delegate, exceptionHandler);
return new ChannelListener() {
public void handleEvent(final T channel) {
try {
channel.shutdownWrites();
} catch (IOException e) {
invokeChannelExceptionHandler(channel, exceptionHandler, e);
return;
}
invokeChannelListener(channel, flushingListener);
}
public String toString() {
return "Write shutdown channel listener -> " + delegate;
}
};
}
/**
* A writing channel listener. Writes the buffer to the channel and then calls the delegate listener. Calls the exception
* handler if an exception occurs. The delegate listener should ensure that the channel write listener is appropriately set.
*
* The returned listener is stateful and will not execute properly if reused.
*
* @param pooled the buffer to write
* @param delegate the delegate listener
* @param exceptionHandler the exception handler
* @param the channel type
* @return the writing channel listener
*/
public static ChannelListener writingChannelListener(final Pooled pooled, final ChannelListener super T> delegate, final ChannelExceptionHandler super T> exceptionHandler) {
return new ChannelListener() {
public void handleEvent(final T channel) {
final ByteBuffer buffer = pooled.getResource();
int result;
boolean ok = false;
do {
try {
result = channel.write(buffer);
ok = true;
} catch (IOException e) {
channel.suspendWrites();
pooled.free();
invokeChannelExceptionHandler(channel, exceptionHandler, e);
return;
} finally {
if (! ok) {
pooled.free();
}
}
if (result == 0) {
Channels.setWriteListener(channel, this);
channel.resumeWrites();
return;
}
} while (buffer.hasRemaining());
pooled.free();
invokeChannelListener(channel, delegate);
}
public String toString() {
return "Writing channel listener -> " + delegate;
}
};
}
/**
* A sending channel listener. Writes the buffer to the channel and then calls the delegate listener. Calls the exception
* handler if an exception occurs. The delegate listener should ensure that the channel write listener is appropriately set.
*
* The returned listener is stateful and will not execute properly if reused.
*
* @param pooled the buffer to send
* @param delegate the delegate listener
* @param exceptionHandler the exception handler
* @param the channel type
* @return the sending channel listener
*/
public static ChannelListener sendingChannelListener(final Pooled pooled, final ChannelListener super T> delegate, final ChannelExceptionHandler super T> exceptionHandler) {
return new ChannelListener() {
public void handleEvent(final T channel) {
final ByteBuffer buffer = pooled.getResource();
boolean free = true;
try {
if (! (free = channel.send(buffer))) {
Channels.setWriteListener(channel, this);
channel.resumeWrites();
return;
}
} catch (IOException e) {
channel.suspendWrites();
pooled.free();
invokeChannelExceptionHandler(channel, exceptionHandler, e);
return;
} finally {
if (free) pooled.free();
}
invokeChannelListener(channel, delegate);
}
public String toString() {
return "Sending channel listener -> " + delegate;
}
};
}
/**
* A file-sending channel listener. Writes the file to the channel and then calls the delegate listener. Calls the exception
* handler if an exception occurs. The delegate listener should ensure that the channel write listener is appropriately set.
*
* The returned listener is stateful and will not execute properly if reused.
*
* @param source the file to read from
* @param position the position in the source file to read from
* @param count the number of bytes to read
* @param delegate the listener to call when the file is sent
* @param exceptionHandler the exception handler to call if a problem occurs
* @param the channel type
* @return the channel listener
*/
public static ChannelListener fileSendingChannelListener(final FileChannel source, final long position, final long count, final ChannelListener super T> delegate, final ChannelExceptionHandler super T> exceptionHandler) {
if (count == 0L) {
return delegatingChannelListener(delegate);
}
return new ChannelListener() {
private long p = position;
private long cnt = count;
public void handleEvent(final T channel) {
long result;
long cnt = this.cnt;
long p = this.p;
try {
do {
try {
result = channel.transferFrom(source, p, cnt);
} catch (IOException e) {
invokeChannelExceptionHandler(channel, exceptionHandler, e);
return;
}
if (result == 0L) {
Channels.setWriteListener(channel, this);
channel.resumeWrites();
return;
}
p += result;
cnt -= result;
} while (cnt > 0L);
// cnt is 0
invokeChannelListener(channel, delegate);
return;
} finally {
this.p = p;
this.cnt = cnt;
}
}
public String toString() {
return "File sending channel listener (" + source + ") -> " + delegate;
}
};
}
/**
* A file-receiving channel listener. Writes the file from the channel and then calls the delegate listener. Calls the exception
* handler if an exception occurs. The delegate listener should ensure that the channel read listener is appropriately set.
*
* The returned listener is stateful and will not execute properly if reused.
*
* @param target the file to write to
* @param position the position in the target file to write to
* @param count the number of bytes to write
* @param delegate the listener to call when the file is sent
* @param exceptionHandler the exception handler to call if a problem occurs
* @param the channel type
* @return the channel listener
*/
public static ChannelListener fileReceivingChannelListener(final FileChannel target, final long position, final long count, final ChannelListener super T> delegate, final ChannelExceptionHandler super T> exceptionHandler) {
if (count == 0L) {
return delegatingChannelListener(delegate);
}
return new ChannelListener() {
private long p = position;
private long cnt = count;
public void handleEvent(final T channel) {
long result;
long cnt = this.cnt;
long p = this.p;
try {
do {
try {
result = channel.transferTo(p, cnt, target);
} catch (IOException e) {
invokeChannelExceptionHandler(channel, exceptionHandler, e);
return;
}
if (result == 0L) {
Channels.setReadListener(channel, this);
channel.resumeReads();
return;
}
p += result;
cnt -= result;
} while (cnt > 0L);
// cnt = 0
invokeChannelListener(channel, delegate);
return;
} finally {
this.p = p;
this.cnt = cnt;
}
}
public String toString() {
return "File receiving channel listener (" + target + ") -> " + delegate;
}
};
}
/**
* A delegating channel listener which passes an event to another listener of the same or a super type.
*
* @param delegate the delegate channel listener
* @param the channel type
* @return the listener
*/
public static ChannelListener delegatingChannelListener(final ChannelListener super T> delegate) {
return new ChannelListener() {
public void handleEvent(final T channel) {
invokeChannelListener(channel, delegate);
}
public String toString() {
return "Delegating channel listener -> " + delegate;
}
};
}
/**
* A delegating channel listener which passes an event to the listener stored in the given setter.
*
* @param channel the channel to pass in
* @param setter the channel listener setter
* @param the listener channel type
* @param the passed in channel type
* @return the listener
*/
public static ChannelListener delegatingChannelListener(final T channel, final ChannelListener.SimpleSetter setter) {
return new SetterDelegatingListener(setter, channel);
}
/**
* A write-suspending channel listener. The returned listener will suspend writes when called. Useful for chaining
* writing listeners to a flush listener to this listener. The delegate listener should ensure that the channel write listener is appropriately set.
*
* @param delegate the delegate channel listener
* @return the suspending channel listener
*/
public static ChannelListener writeSuspendingChannelListener(final ChannelListener super T> delegate) {
return new ChannelListener() {
public void handleEvent(final T channel) {
channel.suspendWrites();
invokeChannelListener(channel, delegate);
}
public String toString() {
return "Write-suspending channel listener -> " + delegate;
}
};
}
/**
* A read-suspending channel listener. The returned listener will suspend read when called.
* The delegate listener should ensure that the channel read listener is appropriately set.
*
* @param delegate the delegate channel listener
* @return the suspending channel listener
*/
public static ChannelListener readSuspendingChannelListener(final ChannelListener super T> delegate) {
return new ChannelListener() {
public void handleEvent(final T channel) {
channel.suspendReads();
invokeChannelListener(channel, delegate);
}
public String toString() {
return "Read-suspending channel listener -> " + delegate;
}
};
}
static final class TransferListener implements ChannelListener {
private final Pooled pooledBuffer;
private final I source;
private final O sink;
private final ChannelListener super I> sourceListener;
private final ChannelListener super O> sinkListener;
private final ChannelExceptionHandler super O> writeExceptionHandler;
private final ChannelExceptionHandler super I> readExceptionHandler;
private long count;
private volatile int state;
TransferListener(final long count, final Pooled pooledBuffer, final I source, final O sink, final ChannelListener super I> sourceListener, final ChannelListener super O> sinkListener, final ChannelExceptionHandler super O> writeExceptionHandler, final ChannelExceptionHandler super I> readExceptionHandler, final int state) {
this.count = count;
this.pooledBuffer = pooledBuffer;
this.source = source;
this.sink = sink;
this.sourceListener = sourceListener;
this.sinkListener = sinkListener;
this.writeExceptionHandler = writeExceptionHandler;
this.readExceptionHandler = readExceptionHandler;
this.state = state;
}
public void handleEvent(final Channel channel) {
final ByteBuffer buffer = pooledBuffer.getResource();
int state = this.state;
// always read after and write before state
long count = this.count;
long lres;
int ires;
switch (state) {
case 0: {
// read listener
for (;;) {
try {
lres = source.transferTo(count, buffer, sink);
} catch (IOException e) {
readFailed(e);
return;
}
if (lres == 0 && !buffer.hasRemaining()) {
this.count = count;
return;
}
if (lres == -1) {
// possibly unexpected EOF
if (count == Long.MAX_VALUE) {
// it's OK; just be done
done();
return;
} else {
readFailed(new EOFException());
return;
}
}
if (count != Long.MAX_VALUE) {
count -= lres;
}
while (buffer.hasRemaining()) {
try {
ires = sink.write(buffer);
} catch (IOException e) {
writeFailed(e);
return;
}
if (count != Long.MAX_VALUE) {
count -= ires;
}
if (ires == 0) {
this.count = count;
this.state = 1;
source.suspendReads();
sink.resumeWrites();
return;
}
}
if (count == 0) {
done();
return;
}
}
}
case 1: {
// write listener
for (;;) {
while (buffer.hasRemaining()) {
try {
ires = sink.write(buffer);
} catch (IOException e) {
writeFailed(e);
return;
}
if (count != Long.MAX_VALUE) {
count -= ires;
}
if (ires == 0) {
return;
}
}
try {
lres = source.transferTo(count, buffer, sink);
} catch (IOException e) {
readFailed(e);
return;
}
if (lres == 0 && !buffer.hasRemaining()) {
this.count = count;
this.state = 0;
sink.suspendWrites();
source.resumeReads();
return;
}
if (lres == -1) {
// possibly unexpected EOF
if (count == Long.MAX_VALUE) {
// it's OK; just be done
done();
return;
} else {
readFailed(new EOFException());
return;
}
}
if (count != Long.MAX_VALUE) {
count -= lres;
}
if (count == 0) {
done();
return;
}
}
}
}
}
private void writeFailed(final IOException e) {
try {
source.suspendReads();
sink.suspendWrites();
invokeChannelExceptionHandler(sink, writeExceptionHandler, e);
} finally {
pooledBuffer.free();
}
}
private void readFailed(final IOException e) {
try {
source.suspendReads();
sink.suspendWrites();
invokeChannelExceptionHandler(source, readExceptionHandler, e);
} finally {
pooledBuffer.free();
}
}
private void done() {
try {
final ChannelListener super I> sourceListener = this.sourceListener;
final ChannelListener super O> sinkListener = this.sinkListener;
final I source = this.source;
final O sink = this.sink;
Channels.setReadListener(source, sourceListener);
if (sourceListener == null) {
source.suspendReads();
} else {
source.wakeupReads();
}
Channels.setWriteListener(sink, sinkListener);
if (sinkListener == null) {
sink.suspendWrites();
} else {
sink.wakeupWrites();
}
} finally {
pooledBuffer.free();
}
}
public String toString() {
return "Transfer channel listener (" + source + " to " + sink + ") -> (" + sourceListener + " and " + sinkListener + ")";
}
}
/**
* Initiate a low-copy transfer between two stream channels. The pool should be a direct buffer pool for best
* performance. The channels will be closed when the transfer completes or if there is an error.
*
* @param source the source channel
* @param sink the target channel
* @param pool the pool from which the transfer buffer should be allocated
* @param the source stream type
* @param the sink stream type
*/
public static void initiateTransfer(final I source, final O sink, Pool pool) {
initiateTransfer(Long.MAX_VALUE, source, sink, CLOSING_CHANNEL_LISTENER, CLOSING_CHANNEL_LISTENER, CLOSING_HANDLER, CLOSING_HANDLER, pool);
}
/**
* Initiate a low-copy transfer between two stream channels. The pool should be a direct buffer pool for best
* performance.
*
* @param count the number of bytes to transfer, or {@link Long#MAX_VALUE} to transfer all remaining bytes
* @param source the source channel
* @param sink the target channel
* @param sourceListener the source listener to set and call when the transfer is complete, or {@code null} to clear the listener at that time
* @param sinkListener the target listener to set and call when the transfer is complete, or {@code null} to clear the listener at that time
* @param readExceptionHandler the read exception handler to call if an error occurs during a read operation
* @param writeExceptionHandler the write exception handler to call if an error occurs during a write operation
* @param pool the pool from which the transfer buffer should be allocated
*/
public static void initiateTransfer(long count, final I source, final O sink, final ChannelListener super I> sourceListener, final ChannelListener super O> sinkListener, final ChannelExceptionHandler super I> readExceptionHandler, final ChannelExceptionHandler super O> writeExceptionHandler, Pool pool) {
if (pool == null) {
throw msg.nullParameter("pool");
}
final Pooled allocated = pool.allocate();
boolean free = true;
try {
final ByteBuffer buffer = allocated.getResource();
long transferred;
for(;;) {
try {
transferred = source.transferTo(count, buffer, sink);
} catch (IOException e) {
invokeChannelExceptionHandler(source, readExceptionHandler, e);
return;
}
if (transferred == 0 && !buffer.hasRemaining()) {
break;
}
if (transferred == -1) {
if (count == Long.MAX_VALUE) {
Channels.setReadListener(source, sourceListener);
if (sourceListener == null) {
source.suspendReads();
} else {
source.wakeupReads();
}
Channels.setWriteListener(sink, sinkListener);
if (sinkListener == null) {
sink.suspendWrites();
} else {
sink.wakeupWrites();
}
} else {
source.suspendReads();
sink.suspendWrites();
invokeChannelExceptionHandler(source, readExceptionHandler, new EOFException());
}
return;
}
if (count != Long.MAX_VALUE) {
count -= transferred;
}
while (buffer.hasRemaining()) {
final int res;
try {
res = sink.write(buffer);
} catch (IOException e) {
invokeChannelExceptionHandler(sink, writeExceptionHandler, e);
return;
}
if (res == 0) {
// write first listener
final TransferListener listener = new TransferListener(count, allocated, source, sink, sourceListener, sinkListener, writeExceptionHandler, readExceptionHandler, 1);
source.suspendReads();
source.getReadSetter().set(listener);
sink.getWriteSetter().set(listener);
sink.resumeWrites();
free = false;
return;
} else if (count != Long.MAX_VALUE) {
count -= res;
}
}
if (count == 0) {
//we are done
Channels.setReadListener(source, sourceListener);
if (sourceListener == null) {
source.suspendReads();
} else {
source.wakeupReads();
}
Channels.setWriteListener(sink, sinkListener);
if (sinkListener == null) {
sink.suspendWrites();
} else {
sink.wakeupWrites();
}
return;
}
}
// read first listener
final TransferListener listener = new TransferListener(count, allocated, source, sink, sourceListener, sinkListener, writeExceptionHandler, readExceptionHandler, 0);
sink.suspendWrites();
sink.getWriteSetter().set(listener);
source.getReadSetter().set(listener);
source.resumeReads();
free = false;
return;
} finally {
if (free) allocated.free();
}
}
/**
* Create a channel listener which automatically drains the given number of bytes from the channel and then calls
* a listener.
*
* @param bytes the number of bytes to drain, or {@code Long.MAX_VALUE} to drain the channel completely
* @param finishListener the listener to call when the drain is complete
* @param exceptionHandler the handler to call if the drain fails
* @param the channel type
* @return the channel listener
*/
public static ChannelListener drainListener(long bytes, ChannelListener super T> finishListener, ChannelExceptionHandler super T> exceptionHandler) {
return new DrainListener(finishListener, exceptionHandler, bytes);
}
private static class DelegatingSetter implements ChannelListener.Setter {
private final ChannelListener.Setter extends Channel> setter;
private final T realChannel;
DelegatingSetter(final ChannelListener.Setter extends Channel> setter, final T realChannel) {
this.setter = setter;
this.realChannel = realChannel;
}
public void set(final ChannelListener super T> channelListener) {
setter.set(channelListener == null ? null : new DelegatingChannelListener(channelListener, realChannel));
}
public String toString() {
return "Delegating setter -> " + setter;
}
}
private static class DelegatingChannelListener implements ChannelListener {
private final ChannelListener super T> channelListener;
private final T realChannel;
public DelegatingChannelListener(final ChannelListener super T> channelListener, final T realChannel) {
this.channelListener = channelListener;
this.realChannel = realChannel;
}
public void handleEvent(final Channel channel) {
invokeChannelListener(realChannel, channelListener);
}
public String toString() {
return "Delegating channel listener -> " + channelListener;
}
}
private static class SetterDelegatingListener implements ChannelListener {
private final SimpleSetter setter;
private final T channel;
public SetterDelegatingListener(final SimpleSetter setter, final T channel) {
this.setter = setter;
this.channel = channel;
}
public void handleEvent(final C channel) {
invokeChannelListener(this.channel, setter.get());
}
public String toString() {
return "Setter delegating channel listener -> " + setter;
}
}
private static final ChannelExceptionHandler CLOSING_HANDLER = new ChannelExceptionHandler() {
public void handleException(final Channel channel, final IOException exception) {
IoUtils.safeClose(channel);
}
};
private static class DrainListener implements ChannelListener {
private final ChannelListener super T> finishListener;
private final ChannelExceptionHandler super T> exceptionHandler;
private long count;
private DrainListener(final ChannelListener super T> finishListener, final ChannelExceptionHandler super T> exceptionHandler, final long count) {
this.finishListener = finishListener;
this.exceptionHandler = exceptionHandler;
this.count = count;
}
public void handleEvent(final T channel) {
try {
long count = this.count;
try {
long res;
for (;;) {
res = Channels.drain(channel, count);
if (res == -1 || res == count) {
this.count = 0L;
invokeChannelListener(channel, finishListener);
return;
} else if (res == 0) {
return;
} else if (count < Long.MAX_VALUE) {
// MAX_VALUE means drain to EOF
count -= res;
}
}
} finally {
this.count = count;
}
} catch (IOException e) {
this.count = 0L;
if (exceptionHandler != null) {
invokeChannelExceptionHandler(channel, exceptionHandler, e);
} else {
IoUtils.safeShutdownReads(channel);
}
}
}
public String toString() {
return "Draining channel listener (" + count + " bytes) -> " + finishListener;
}
}
}
xnio-3.3.2.Final/api/src/main/java/org/xnio/ChannelPipe.java 0000664 0000000 0000000 00000003115 12570160607 0023532 0 ustar 00root root 0000000 0000000 /*
* JBoss, Home of Professional Open Source.
*
* Copyright 2012 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 org.xnio.channels.CloseableChannel;
/**
* A one-way pipe.
*
* @author David M. Lloyd
*/
public final class ChannelPipe {
private final L leftSide;
private final R rightSide;
/**
* Construct a new instance.
*
* @param leftSide the pipe left side
* @param rightSide the pipe right side
*/
public ChannelPipe(final L leftSide, final R rightSide) {
this.rightSide = rightSide;
this.leftSide = leftSide;
}
/**
* Get the pipe source.
*
* @return the pipe source
*/
public L getLeftSide() {
return leftSide;
}
/**
* Get the pipe sink.
*
* @return the pipe sink
*/
public R getRightSide() {
return rightSide;
}
}
xnio-3.3.2.Final/api/src/main/java/org/xnio/ChannelSource.java 0000664 0000000 0000000 00000001137 12570160607 0024077 0 ustar 00root root 0000000 0000000
package org.xnio;
import java.nio.channels.Channel;
/**
* A channel source. Instances of this interface are used to create a channel and associate it with a listener. Example
* uses are to establish a TCP connection (as a client), open a serial port, etc.
*
* @param the type of channel
*/
public interface ChannelSource {
/**
* Open a channel.
*
* @param openListener the listener which will be notified when the channel is open
* @return the future result of this operation
*/
IoFuture