/*
* JBoss, Home of Professional Open Source.
* Copyright 2012 Red Hat, Inc., 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.nio.test;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import org.jboss.logging.Logger;
import org.junit.Test;
import org.xnio.ChannelListener;
import org.xnio.ChannelPipe;
import org.xnio.IoUtils;
import org.xnio.Options;
import org.xnio.XnioWorker;
import org.xnio.channels.StreamChannel;
/**
* Test for full duplex channel pipe usage.
*
* @author <a href="mailto:flavia.rainone@jboss.com">Flavia Rainone</a>
*/
public final class NioFullDuplexChannelPipeTestCase extends AbstractNioChannelPipeTest<StreamChannel, StreamChannel> {
private static final Logger log = Logger.getLogger("TEST");
@Override
protected ChannelPipe<StreamChannel, StreamChannel> createPipeChannel(XnioWorker worker) throws IOException {
return worker.createFullDuplexPipe();
}
@Test
public void leftChannelClose() throws Exception {
log.info("Test: leftChannelClose");
final CountDownLatch latch = new CountDownLatch(4);
doConnectionTest(new LatchAwaiter(latch), new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
log.info("In pipe creation, leftChannel setup");
try {
channel.getCloseSetter().set(new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
log.info("In left channel close");
latch.countDown();
}
});
channel.close();
leftChannelOK.set(true);
latch.countDown();
} catch (Throwable t) {
log.error("In left channel", t);
latch.countDown();
throw new RuntimeException(t);
}
}
}, new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
log.info("In pipe creation, rightChannel setup");
channel.getCloseSetter().set(new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
log.info("In right channel close");
latch.countDown();
}
});
channel.getReadSetter().set(new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
log.info("In right channel readable");
try {
final int c = channel.read(ByteBuffer.allocate(100));
if (c == -1) {
rightChannelOK.set(true);
}
channel.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
latch.countDown();
}
});
channel.resumeReads();
}
});
}
@Test
public void rightChannelClose() throws Exception {
log.info("Test: rightChannelClose");
final CountDownLatch latch = new CountDownLatch(2);
doConnectionTest(new LatchAwaiter(latch), new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
try {
channel.getCloseSetter().set(new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
latch.countDown();
}
});
channel.getReadSetter().set(new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
try {
final int c = channel.read(ByteBuffer.allocate(100));
if (c == -1) {
leftChannelOK.set(true);
channel.close();
return;
}
// retry
return;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
channel.resumeReads();
} catch (Throwable t) {
try {
channel.close();
} catch (Throwable t2) {
log.errorf(t2, "Failed to close channel (propagating as RT exception)");
latch.countDown();
throw new RuntimeException(t);
}
throw new RuntimeException(t);
}
}
}, new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
try {
channel.getCloseSetter().set(new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
rightChannelOK.set(true);
latch.countDown();
}
});
channel.close();
} catch (Throwable t) {
log.errorf(t, "Failed to close channel (propagating as RT exception)");
latch.countDown();
throw new RuntimeException(t);
}
}
});
}
@Test
public void twoWayTransfer() throws Exception {
log.info("Test: twoWayTransfer");
final CountDownLatch latch = new CountDownLatch(2);
final AtomicInteger leftChannelSent = new AtomicInteger(0);
final AtomicInteger leftChannelReceived = new AtomicInteger(0);
final AtomicInteger rightChannelSent = new AtomicInteger(0);
final AtomicInteger rightChannelReceived = new AtomicInteger(0);
doConnectionTest(new LatchAwaiter(latch), new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
channel.getCloseSetter().set(new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
latch.countDown();
}
});
channel.getReadSetter().set(new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
try {
int c;
while ((c = channel.read(ByteBuffer.allocate(100))) > 0) {
leftChannelReceived.addAndGet(c);
}
if (c == -1) {
channel.shutdownReads();
}
} catch (Throwable t) {
log.errorf(t, "Failed to close channel (propagating as RT exception)");
throw new RuntimeException(t);
}
}
});
final ByteBuffer buffer = ByteBuffer.allocate(100);
try {
buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip();
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
channel.getWriteSetter().set(new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
try {
int c;
while ((c = channel.write(buffer)) > 0) {
if (leftChannelSent.addAndGet(c) > 1000) {
final ChannelListener<StreamChannel> listener = new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
try {
channel.shutdownWrites();
} catch (Throwable t) {
log.errorf(t, "Failed to close channel (propagating as RT exception)");
throw new RuntimeException(t);
}
}
};
channel.getWriteSetter().set(listener);
listener.handleEvent(channel);
return;
}
buffer.rewind();
}
} catch (Throwable t) {
log.errorf(t, "Failed to close channel (propagating as RT exception)");
throw new RuntimeException(t);
}
}
});
channel.resumeReads();
channel.resumeWrites();
}
}, new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
channel.getCloseSetter().set(new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
latch.countDown();
}
});
channel.getReadSetter().set(new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
try {
int c;
while ((c = channel.read(ByteBuffer.allocate(100))) > 0) {
rightChannelReceived.addAndGet(c);
}
if (c == -1) {
channel.shutdownReads();
}
} catch (Throwable t) {
log.errorf(t, "Failed to close channel (propagating as RT exception)");
throw new RuntimeException(t);
}
}
});
final ByteBuffer buffer = ByteBuffer.allocate(100);
try {
buffer.put("This Is A Test Gumma\r\n".getBytes("UTF-8")).flip();
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
channel.getWriteSetter().set(new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
try {
int c;
while ((c = channel.write(buffer)) > 0) {
if (rightChannelSent.addAndGet(c) > 1000) {
final ChannelListener<StreamChannel> listener = new ChannelListener<StreamChannel>() {
public void handleEvent(final StreamChannel channel) {
try {
channel.shutdownWrites();
} catch (Throwable t) {
log.errorf(t, "Failed to close channel (propagating as RT exception)");
throw new RuntimeException(t);
}
}
};
channel.getWriteSetter().set(listener);
listener.handleEvent(channel);
return;
}
buffer.rewind();
}
} catch (Throwable t) {
log.errorf(t, "Failed to close channel (propagating as RT exception)");
throw new RuntimeException(t);
}
}
});
channel.resumeReads();
channel.resumeWrites();
}
});
assertEquals(rightChannelSent.get(), leftChannelReceived.get());
assertEquals(leftChannelSent.get(), rightChannelReceived.get());
leftChannelOK.set(true);
rightChannelOK.set(true);
}
}