Ported the QOTM example to the new API
- Fixed bugs in the NIO datagram transports - DefaultNioDatagramChannelConfig did not initialize on Java 6
This commit is contained in:
parent
c6f3b5762e
commit
c7c923cab3
@ -15,21 +15,18 @@
|
||||
*/
|
||||
package io.netty.example.qotm;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import io.netty.bootstrap.ConnectionlessBootstrap;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.ChannelPipelineFactory;
|
||||
import io.netty.channel.Channels;
|
||||
import io.netty.channel.FixedReceiveBufferSizePredictorFactory;
|
||||
import io.netty.channel.socket.DatagramChannel;
|
||||
import io.netty.channel.socket.DatagramChannelFactory;
|
||||
import io.netty.channel.socket.nio.NioDatagramChannelFactory;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import io.netty.handler.codec.string.StringEncoder;
|
||||
import io.netty.buffer.ChannelBuffers;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelBootstrap;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
import io.netty.channel.socket.nio.NioDatagramChannel;
|
||||
import io.netty.channel.socket.nio.SelectorEventLoop;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* A UDP broadcast client that asks for a quote of the moment (QOTM) to
|
||||
* {@link QuoteOfTheMomentServer}.
|
||||
@ -44,53 +41,36 @@ public class QuoteOfTheMomentClient {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
DatagramChannelFactory f =
|
||||
new NioDatagramChannelFactory(Executors.newCachedThreadPool());
|
||||
public void run() throws Exception {
|
||||
ChannelBootstrap b = new ChannelBootstrap();
|
||||
try {
|
||||
b.eventLoop(new SelectorEventLoop())
|
||||
.channel(new NioDatagramChannel())
|
||||
.localAddress(new InetSocketAddress(0))
|
||||
.option(ChannelOption.SO_BROADCAST, true)
|
||||
.initializer(new ChannelInitializer() {
|
||||
@Override
|
||||
public void initChannel(Channel ch) throws Exception {
|
||||
ch.pipeline().addLast(new QuoteOfTheMomentClientHandler());
|
||||
}
|
||||
});
|
||||
|
||||
ConnectionlessBootstrap b = new ConnectionlessBootstrap(f);
|
||||
Channel ch = b.bind().sync().channel();
|
||||
|
||||
// Configure the pipeline factory.
|
||||
b.setPipelineFactory(new ChannelPipelineFactory() {
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
return Channels.pipeline(
|
||||
new StringEncoder(CharsetUtil.ISO_8859_1),
|
||||
new StringDecoder(CharsetUtil.ISO_8859_1),
|
||||
new QuoteOfTheMomentClientHandler());
|
||||
// Broadcast the QOTM request to port 8080.
|
||||
ch.write(new DatagramPacket(
|
||||
ChannelBuffers.copiedBuffer("QOTM?", CharsetUtil.UTF_8),
|
||||
new InetSocketAddress("255.255.255.255", port)));
|
||||
|
||||
// QuoteOfTheMomentClientHandler will close the DatagramChannel when a
|
||||
// response is received. If the channel is not closed within 5 seconds,
|
||||
// print an error message and quit.
|
||||
if (!ch.closeFuture().await(5000)) {
|
||||
System.err.println("QOTM request timed out.");
|
||||
}
|
||||
});
|
||||
|
||||
// Enable broadcast
|
||||
b.setOption("broadcast", "true");
|
||||
|
||||
// Allow packets as large as up to 1024 bytes (default is 768).
|
||||
// You could increase or decrease this value to avoid truncated packets
|
||||
// or to improve memory footprint respectively.
|
||||
//
|
||||
// Please also note that a large UDP packet might be truncated or
|
||||
// dropped by your router no matter how you configured this option.
|
||||
// In UDP, a packet is truncated or dropped if it is larger than a
|
||||
// certain size, depending on router configuration. IPv4 routers
|
||||
// truncate and IPv6 routers drop a large packet. That's why it is
|
||||
// safe to send small packets in UDP.
|
||||
b.setOption(
|
||||
"receiveBufferSizePredictorFactory",
|
||||
new FixedReceiveBufferSizePredictorFactory(1024));
|
||||
|
||||
DatagramChannel c = (DatagramChannel) b.bind(new InetSocketAddress(0));
|
||||
|
||||
// Broadcast the QOTM request to port 8080.
|
||||
c.write("QOTM?", new InetSocketAddress("255.255.255.255", port));
|
||||
|
||||
// QuoteOfTheMomentClientHandler will close the DatagramChannel when a
|
||||
// response is received. If the channel is not closed within 5 seconds,
|
||||
// print an error message and quit.
|
||||
if (!c.getCloseFuture().awaitUninterruptibly(5000)) {
|
||||
System.err.println("QOTM request timed out.");
|
||||
c.close().awaitUninterruptibly();
|
||||
} finally {
|
||||
b.shutdown();
|
||||
}
|
||||
|
||||
f.releaseExternalResources();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
@ -15,27 +15,30 @@
|
||||
*/
|
||||
package io.netty.example.qotm;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ExceptionEvent;
|
||||
import io.netty.channel.MessageEvent;
|
||||
import io.netty.channel.SimpleChannelUpstreamHandler;
|
||||
import io.netty.channel.ChannelInboundHandlerContext;
|
||||
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
public class QuoteOfTheMomentClientHandler extends ChannelInboundMessageHandlerAdapter<DatagramPacket> {
|
||||
|
||||
public class QuoteOfTheMomentClientHandler extends SimpleChannelUpstreamHandler {
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
|
||||
public void messageReceived(
|
||||
ChannelInboundHandlerContext<DatagramPacket> ctx, DatagramPacket msg)
|
||||
throws Exception {
|
||||
String msg = (String) e.getMessage();
|
||||
if (msg.startsWith("QOTM: ")) {
|
||||
System.out.println("Quote of the Moment: " + msg.substring(6));
|
||||
e.channel().close();
|
||||
String response = msg.data().toString(CharsetUtil.UTF_8);
|
||||
if (response.startsWith("QOTM: ")) {
|
||||
System.out.println("Quote of the Moment: " + response.substring(6));
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
|
||||
public void exceptionCaught(
|
||||
ChannelInboundHandlerContext<DatagramPacket> ctx, Throwable cause)
|
||||
throws Exception {
|
||||
e.cause().printStackTrace();
|
||||
e.channel().close();
|
||||
cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
|
@ -15,19 +15,14 @@
|
||||
*/
|
||||
package io.netty.example.qotm;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.Executors;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelBootstrap;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.socket.nio.NioDatagramChannel;
|
||||
import io.netty.channel.socket.nio.SelectorEventLoop;
|
||||
|
||||
import io.netty.bootstrap.ConnectionlessBootstrap;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.ChannelPipelineFactory;
|
||||
import io.netty.channel.Channels;
|
||||
import io.netty.channel.FixedReceiveBufferSizePredictorFactory;
|
||||
import io.netty.channel.socket.DatagramChannelFactory;
|
||||
import io.netty.channel.socket.nio.NioDatagramChannelFactory;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import io.netty.handler.codec.string.StringEncoder;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* A UDP server that responds to the QOTM (quote of the moment) request to a
|
||||
@ -43,41 +38,24 @@ public class QuoteOfTheMomentServer {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
DatagramChannelFactory f =
|
||||
new NioDatagramChannelFactory(Executors.newCachedThreadPool());
|
||||
public void run() throws Exception {
|
||||
ChannelBootstrap b = new ChannelBootstrap();
|
||||
try {
|
||||
b.eventLoop(new SelectorEventLoop())
|
||||
.channel(new NioDatagramChannel())
|
||||
.localAddress(new InetSocketAddress(port))
|
||||
.option(ChannelOption.SO_BROADCAST, true)
|
||||
.initializer(new ChannelInitializer() {
|
||||
@Override
|
||||
public void initChannel(Channel ch) throws Exception {
|
||||
ch.pipeline().addLast(new QuoteOfTheMomentServerHandler());
|
||||
}
|
||||
});
|
||||
|
||||
ConnectionlessBootstrap b = new ConnectionlessBootstrap(f);
|
||||
|
||||
// Configure the pipeline factory.
|
||||
b.setPipelineFactory(new ChannelPipelineFactory() {
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
return Channels.pipeline(
|
||||
new StringEncoder(CharsetUtil.ISO_8859_1),
|
||||
new StringDecoder(CharsetUtil.ISO_8859_1),
|
||||
new QuoteOfTheMomentServerHandler());
|
||||
}
|
||||
});
|
||||
|
||||
// Enable broadcast
|
||||
b.setOption("broadcast", "false");
|
||||
|
||||
// Allow packets as large as up to 1024 bytes (default is 768).
|
||||
// You could increase or decrease this value to avoid truncated packets
|
||||
// or to improve memory footprint respectively.
|
||||
//
|
||||
// Please also note that a large UDP packet might be truncated or
|
||||
// dropped by your router no matter how you configured this option.
|
||||
// In UDP, a packet is truncated or dropped if it is larger than a
|
||||
// certain size, depending on router configuration. IPv4 routers
|
||||
// truncate and IPv6 routers drop a large packet. That's why it is
|
||||
// safe to send small packets in UDP.
|
||||
b.setOption(
|
||||
"receiveBufferSizePredictorFactory",
|
||||
new FixedReceiveBufferSizePredictorFactory(1024));
|
||||
|
||||
// Bind to the port and start the service.
|
||||
b.bind(new InetSocketAddress(port));
|
||||
b.bind().sync().channel().closeFuture().await();
|
||||
} finally {
|
||||
b.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
@ -15,14 +15,15 @@
|
||||
*/
|
||||
package io.netty.example.qotm;
|
||||
|
||||
import io.netty.buffer.ChannelBuffers;
|
||||
import io.netty.channel.ChannelInboundHandlerContext;
|
||||
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ExceptionEvent;
|
||||
import io.netty.channel.MessageEvent;
|
||||
import io.netty.channel.SimpleChannelUpstreamHandler;
|
||||
|
||||
public class QuoteOfTheMomentServerHandler extends SimpleChannelUpstreamHandler {
|
||||
public class QuoteOfTheMomentServerHandler extends ChannelInboundMessageHandlerAdapter<DatagramPacket> {
|
||||
|
||||
private static final Random random = new Random();
|
||||
|
||||
@ -43,18 +44,21 @@ public class QuoteOfTheMomentServerHandler extends SimpleChannelUpstreamHandler
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
|
||||
public void messageReceived(
|
||||
ChannelInboundHandlerContext<DatagramPacket> ctx, DatagramPacket msg)
|
||||
throws Exception {
|
||||
String msg = (String) e.getMessage();
|
||||
if (msg.equals("QOTM?")) {
|
||||
e.channel().write("QOTM: " + nextQuote(), e.getRemoteAddress());
|
||||
if (msg.data().toString(CharsetUtil.UTF_8).equals("QOTM?")) {
|
||||
ctx.write(new DatagramPacket(
|
||||
ChannelBuffers.copiedBuffer("QOTM: " + nextQuote(), CharsetUtil.UTF_8),
|
||||
msg.remoteAddress()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
|
||||
public void exceptionCaught(
|
||||
ChannelInboundHandlerContext<DatagramPacket> ctx, Throwable cause)
|
||||
throws Exception {
|
||||
e.cause().printStackTrace();
|
||||
cause.printStackTrace();
|
||||
// We don't close the channel because we can keep serving requests.
|
||||
}
|
||||
}
|
||||
|
@ -42,29 +42,29 @@ class DefaultNioDatagramChannelConfig extends DefaultDatagramChannelConfig {
|
||||
}
|
||||
|
||||
Object ipMulticastIf = null;
|
||||
Method getOption = null;
|
||||
Method setOption = null;
|
||||
if (socketOptionType != null) {
|
||||
try {
|
||||
ipMulticastIf = Class.forName("java.net.StandardSocketOptions", true, classLoader).getDeclaredField("IP_MULTICAST_IF").get(null);
|
||||
} catch (Exception e) {
|
||||
throw new Error("cannot locate the IP_MULTICAST_IF field", e);
|
||||
}
|
||||
|
||||
try {
|
||||
getOption = DatagramChannel.class.getDeclaredMethod("getOption", socketOptionType);
|
||||
} catch (Exception e) {
|
||||
throw new Error("cannot locate the getOption() method", e);
|
||||
}
|
||||
|
||||
try {
|
||||
setOption = DatagramChannel.class.getDeclaredMethod("setOption", socketOptionType, Object.class);
|
||||
} catch (Exception e) {
|
||||
throw new Error("cannot locate the setOption() method", e);
|
||||
}
|
||||
}
|
||||
IP_MULTICAST_IF = ipMulticastIf;
|
||||
|
||||
Method getOption;
|
||||
try {
|
||||
getOption = DatagramChannel.class.getDeclaredMethod("getOption", socketOptionType);
|
||||
} catch (Exception e) {
|
||||
throw new Error("cannot locate the getOption() method", e);
|
||||
}
|
||||
GET_OPTION = getOption;
|
||||
|
||||
Method setOption;
|
||||
try {
|
||||
setOption = DatagramChannel.class.getDeclaredMethod("setOption", socketOptionType, Object.class);
|
||||
} catch (Exception e) {
|
||||
throw new Error("cannot locate the setOption() method", e);
|
||||
}
|
||||
SET_OPTION = setOption;
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ public final class NioDatagramChannel extends AbstractNioChannel implements io.n
|
||||
|
||||
@Override
|
||||
protected void doBind(SocketAddress localAddress) throws Exception {
|
||||
javaChannel().bind(localAddress);
|
||||
javaChannel().socket().bind(localAddress);
|
||||
selectionKey().interestOps(SelectionKey.OP_READ);
|
||||
}
|
||||
|
||||
@ -174,6 +174,7 @@ public final class NioDatagramChannel extends AbstractNioChannel implements io.n
|
||||
@Override
|
||||
protected int doRead(ChannelBufferHolder<Object> buf) throws Exception {
|
||||
DatagramChannel ch = javaChannel();
|
||||
// FIXME: Make this configurable.
|
||||
ByteBuffer data = ByteBuffer.allocate(1024);
|
||||
InetSocketAddress remoteAddress = (InetSocketAddress) ch.receive(data);
|
||||
if (remoteAddress == null) {
|
||||
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.bootstrap;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/**
|
||||
* A test to make sure that a bootstrap can recognize ordered maps
|
||||
*/
|
||||
public class BootstrapOrderedMapTest {
|
||||
|
||||
@Test
|
||||
public void shouldReturnTrueIfLinkedHashMap() {
|
||||
assertTrue(Bootstrap.isOrderedMap(new LinkedHashMap<String, String>()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnTrueIfMapImplementsOrderedMap() {
|
||||
assertTrue(Bootstrap.isOrderedMap(new DummyOrderedMap<String, String>()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnFalseIfMapHasNoDefaultConstructor() {
|
||||
assertFalse(Bootstrap.isOrderedMap(
|
||||
new MapWithoutDefaultConstructor<String, String>(
|
||||
new HashMap<String, String>())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnFalseIfMapIsNotOrdered() {
|
||||
assertFalse(Bootstrap.isOrderedMap(new HashMap<String, String>()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnTrueIfMapIsOrdered() {
|
||||
assertTrue(Bootstrap.isOrderedMap(new UnknownOrderedMap<String, String>()));
|
||||
}
|
||||
|
||||
interface OrderedMap {
|
||||
// A tag interface
|
||||
}
|
||||
|
||||
static class DummyOrderedMap<K,V> extends AbstractMap<K, V> implements OrderedMap {
|
||||
|
||||
private final Map<K, V> map = new HashMap<K, V>();
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return map.entrySet();
|
||||
}
|
||||
}
|
||||
|
||||
static class MapWithoutDefaultConstructor<K, V> extends AbstractMap<K, V> {
|
||||
private final Map<K, V> map;
|
||||
|
||||
MapWithoutDefaultConstructor(Map<K, V> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return map.entrySet();
|
||||
}
|
||||
}
|
||||
|
||||
static class UnknownOrderedMap<K,V> extends AbstractMap<K, V> {
|
||||
|
||||
private final Map<K, V> map = new LinkedHashMap<K, V>();
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return map.entrySet();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,359 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you 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 io.netty.bootstrap;
|
||||
|
||||
import static org.easymock.EasyMock.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import io.netty.channel.ChannelDownstreamHandler;
|
||||
import io.netty.channel.ChannelEvent;
|
||||
import io.netty.channel.ChannelFactory;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.ChannelPipelineFactory;
|
||||
import io.netty.channel.ChannelUpstreamHandler;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/**
|
||||
* A bootstrap test
|
||||
*/
|
||||
public class BootstrapTest {
|
||||
|
||||
/**
|
||||
* Tests to make sure that a new bootstrap should not return null, but an IllegalStateException
|
||||
*/
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void shouldNotReturnNullFactory() {
|
||||
new Bootstrap().getFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure that a new bootstrap cannot have it's channel factory changed
|
||||
*/
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void shouldNotAllowInitialFactoryToChange() {
|
||||
new Bootstrap(createMock(ChannelFactory.class)).setFactory(createMock(ChannelFactory.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure that a bootstrap's factory can only be set once and not reset after that
|
||||
*/
|
||||
@Test
|
||||
public void shouldNotAllowFactoryToChangeMoreThanOnce() {
|
||||
//Initialize a new bootstrap
|
||||
Bootstrap b = new Bootstrap();
|
||||
//Create a mock-up ChannelFactory
|
||||
ChannelFactory f = createMock(ChannelFactory.class);
|
||||
//Set the bootstrap's channel factory
|
||||
b.setFactory(f);
|
||||
//Assert that both f and the bootstrap's factory are the same
|
||||
assertSame(f, b.getFactory());
|
||||
|
||||
//Start a try block
|
||||
try {
|
||||
//Attempt to set the bootstrap's channel factory again
|
||||
b.setFactory(createMock(ChannelFactory.class));
|
||||
//Fail if no exception is thrown
|
||||
fail();
|
||||
} catch (IllegalStateException e) {
|
||||
// Success.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure that setFactory does not accept null as a parameter
|
||||
*/
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void shouldNotAllowNullFactory() {
|
||||
new Bootstrap().setFactory(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure that a new bootstrap's default pipeline is not null
|
||||
*/
|
||||
@Test
|
||||
public void shouldHaveNonNullInitialPipeline() {
|
||||
assertNotNull(new Bootstrap().getPipeline());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure a bootstrap's pipeline cannot be set to null
|
||||
*/
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void shouldNotAllowNullPipeline() {
|
||||
new Bootstrap().setPipeline(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure a bootstrap cannot have it's pipeline (map) set to null
|
||||
*/
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void shouldNotAllowNullPipelineMap() {
|
||||
new Bootstrap().setPipelineAsMap(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure a bootstrap's initial pipeline factory is not null
|
||||
*/
|
||||
@Test
|
||||
public void shouldHaveNonNullInitialPipelineFactory() {
|
||||
assertNotNull(new Bootstrap().getPipelineFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure that a bootstrap's pipeline factory changes if a new pipeline is set
|
||||
*/
|
||||
@Test
|
||||
public void shouldUpdatePipelineFactoryIfPipelineIsSet() {
|
||||
//Make a new bootstrap
|
||||
Bootstrap b = new Bootstrap();
|
||||
//Get the initial pipeline factory
|
||||
ChannelPipelineFactory oldPipelineFactory = b.getPipelineFactory();
|
||||
//Set a new pipeline
|
||||
b.setPipeline(createMock(ChannelPipeline.class));
|
||||
//Assert that the new pipeline factory is not the same as the initial one
|
||||
assertNotSame(oldPipelineFactory, b.getPipelineFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure a bootstrap's pipeline is not returned when a pipeline factory is explicitly set
|
||||
*/
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void shouldNotReturnPipelineWhenPipelineFactoryIsSetByUser() {
|
||||
Bootstrap b = new Bootstrap();
|
||||
b.setPipelineFactory(createMock(ChannelPipelineFactory.class));
|
||||
b.getPipeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure a bootstrap's pipeline map is not returned when a pipeline factory is explicitly set
|
||||
*/
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void shouldNotReturnPipelineMapWhenPipelineFactoryIsSetByUser() {
|
||||
Bootstrap b = new Bootstrap();
|
||||
b.setPipelineFactory(createMock(ChannelPipelineFactory.class));
|
||||
b.getPipelineAsMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure a bootstrap's pipeline factory cannot be set to null
|
||||
*/
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void shouldNotAllowNullPipelineFactory() {
|
||||
new Bootstrap().setPipelineFactory(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure a new bootstrap's pipeline map is empty
|
||||
*/
|
||||
@Test
|
||||
public void shouldHaveInitialEmptyPipelineMap() {
|
||||
assertTrue(new Bootstrap().getPipelineAsMap().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure that a buffer's pipeline map is ordered
|
||||
*/
|
||||
@Test
|
||||
public void shouldReturnOrderedPipelineMap() {
|
||||
Bootstrap b = new Bootstrap();
|
||||
ChannelPipeline p = b.getPipeline();
|
||||
p.addLast("a", new DummyHandler());
|
||||
p.addLast("b", new DummyHandler());
|
||||
p.addLast("c", new DummyHandler());
|
||||
p.addLast("d", new DummyHandler());
|
||||
|
||||
Iterator<Entry<String, ChannelHandler>> m =
|
||||
b.getPipelineAsMap().entrySet().iterator();
|
||||
Entry<String, ChannelHandler> e;
|
||||
e = m.next();
|
||||
assertEquals("a", e.getKey());
|
||||
assertSame(p.get("a"), e.getValue());
|
||||
e = m.next();
|
||||
assertEquals("b", e.getKey());
|
||||
assertSame(p.get("b"), e.getValue());
|
||||
e = m.next();
|
||||
assertEquals("c", e.getKey());
|
||||
assertSame(p.get("c"), e.getValue());
|
||||
e = m.next();
|
||||
assertEquals("d", e.getKey());
|
||||
assertSame(p.get("d"), e.getValue());
|
||||
|
||||
assertFalse(m.hasNext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure that a buffer's pipeline map cannot be set to an unordered map
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldNotAllowUnorderedPipelineMap() {
|
||||
Map<String, ChannelHandler> m = new HashMap<String, ChannelHandler>();
|
||||
m.put("a", new DummyHandler());
|
||||
m.put("b", new DummyHandler());
|
||||
m.put("c", new DummyHandler());
|
||||
m.put("d", new DummyHandler());
|
||||
|
||||
Bootstrap b = new Bootstrap();
|
||||
b.setPipelineAsMap(m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure a buffer's pipeline is ordered when it is set from a map
|
||||
*/
|
||||
@Test
|
||||
public void shouldHaveOrderedPipelineWhenSetFromMap() {
|
||||
Map<String, ChannelHandler> m = new LinkedHashMap<String, ChannelHandler>();
|
||||
m.put("a", new DummyHandler());
|
||||
m.put("b", new DummyHandler());
|
||||
m.put("c", new DummyHandler());
|
||||
m.put("d", new DummyHandler());
|
||||
|
||||
Bootstrap b = new Bootstrap();
|
||||
b.setPipelineAsMap(m);
|
||||
|
||||
ChannelPipeline p = b.getPipeline();
|
||||
|
||||
assertSame(p.first(), m.get("a"));
|
||||
assertEquals("a", p.context(p.first()).name());
|
||||
p.removeFirst();
|
||||
assertSame(p.first(), m.get("b"));
|
||||
assertEquals("b", p.context(p.first()).name());
|
||||
p.removeFirst();
|
||||
assertSame(p.first(), m.get("c"));
|
||||
assertEquals("c", p.context(p.first()).name());
|
||||
p.removeFirst();
|
||||
assertSame(p.first(), m.get("d"));
|
||||
assertEquals("d", p.context(p.first()).name());
|
||||
p.removeFirst();
|
||||
|
||||
try {
|
||||
p.removeFirst();
|
||||
fail();
|
||||
} catch (NoSuchElementException e) {
|
||||
// Success.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure that a new bootstrap should not have any options set
|
||||
*/
|
||||
@Test
|
||||
public void shouldHaveInitialEmptyOptionMap() {
|
||||
assertTrue(new Bootstrap().getOptions().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure that a bootstrap's option map updates in real time
|
||||
*/
|
||||
@Test
|
||||
public void shouldUpdateOptionMapAsRequested1() {
|
||||
Bootstrap b = new Bootstrap();
|
||||
b.setOption("s", "x");
|
||||
b.setOption("b", true);
|
||||
b.setOption("i", 42);
|
||||
|
||||
Map<String, Object> o = b.getOptions();
|
||||
assertEquals(3, o.size());
|
||||
assertEquals("x", o.get("s"));
|
||||
assertEquals(true, o.get("b"));
|
||||
assertEquals(42, o.get("i"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure that a bootstrap's option map updates in real time
|
||||
*/
|
||||
@Test
|
||||
public void shouldUpdateOptionMapAsRequested2() {
|
||||
Bootstrap b = new Bootstrap();
|
||||
Map<String, Object> o1 = new HashMap<String, Object>();
|
||||
o1.put("s", "x");
|
||||
o1.put("b", true);
|
||||
o1.put("i", 42);
|
||||
b.setOptions(o1);
|
||||
|
||||
Map<String, Object> o2 = b.getOptions();
|
||||
assertEquals(3, o2.size());
|
||||
assertEquals("x", o2.get("s"));
|
||||
assertEquals(true, o2.get("b"));
|
||||
assertEquals(42, o2.get("i"));
|
||||
|
||||
assertNotSame(o1, o2);
|
||||
assertEquals(o1, o2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure that an option is removed from a buffer's options when the option is set to null
|
||||
*/
|
||||
@Test
|
||||
public void shouldRemoveOptionIfValueIsNull() {
|
||||
Bootstrap b = new Bootstrap();
|
||||
|
||||
b.setOption("s", "x");
|
||||
assertEquals("x", b.getOption("s"));
|
||||
|
||||
b.setOption("s", null);
|
||||
assertNull(b.getOption("s"));
|
||||
assertTrue(b.getOptions().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure that a bootstrap can't accept null as a parameter of getOption(key)
|
||||
*/
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void shouldNotAllowNullOptionKeyOnGet() {
|
||||
new Bootstrap().getOption(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure a bootstrap can't accept a null key when using setOption(key, value)
|
||||
*/
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void shouldNotAllowNullOptionKeyOnSet() {
|
||||
new Bootstrap().setOption(null, "x");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to make sure that a boostrap can't accept a null option map
|
||||
*/
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void shouldNotAllowNullOptionMap() {
|
||||
new Bootstrap().setOptions(null);
|
||||
}
|
||||
|
||||
private class DummyHandler implements ChannelUpstreamHandler, ChannelDownstreamHandler {
|
||||
|
||||
public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e)
|
||||
throws Exception {
|
||||
ctx.sendUpstream(e);
|
||||
}
|
||||
|
||||
public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e)
|
||||
throws Exception {
|
||||
ctx.sendDownstream(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user