Yuta HIGUCHI
Committed by Gerrit Code Review

Workaround for NoClassDefFound issue in Netty.

SimpleChannelInboundHandler generates `message` instance check code on the fly,
using JavaAssist. Which was not working, when a new Connection was created on the thread
outside of NettyMessagingManager bundle, which did not have access to netty classes.
- Implemented equivalent for SimpleChannelInboundHandler<InternaleMessage>
  without specifying type parameter, avoiding on the fly code generation.

Other changes:
- Add a method in IpAddress to return InetAddress instance.

Change-Id: Ie97294a5650683457b9395e773269c5232d8e602
......@@ -23,5 +23,4 @@ osgi_jar_with_tests (
deps = COMPILE_DEPS,
test_deps = TEST_DEPS,
visibility = ['PUBLIC'],
dynamicimport_packages = 'io.netty.*',
)
......
......@@ -116,22 +116,4 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<DynamicImport-Package>
io.netty.*
</DynamicImport-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
......
......@@ -32,7 +32,11 @@ import java.io.IOException;
* Encode InternalMessage out into a byte buffer.
*/
@Sharable
public class MessageEncoder extends MessageToByteEncoder<InternalMessage> {
public class MessageEncoder extends MessageToByteEncoder<Object> {
// Effectively MessageToByteEncoder<InternalMessage>,
// had to specify <Object> to avoid Class Loader not being able to find some classes.
private final Logger log = LoggerFactory.getLogger(getClass());
private final int preamble;
......@@ -41,14 +45,15 @@ public class MessageEncoder extends MessageToByteEncoder<InternalMessage> {
this.preamble = preamble;
}
private final Logger log = LoggerFactory.getLogger(getClass());
@Override
protected void encode(
ChannelHandlerContext context,
InternalMessage message,
Object rawMessage,
ByteBuf out) throws Exception {
InternalMessage message = (InternalMessage) rawMessage;
out.writeInt(this.preamble);
// write time
......@@ -100,4 +105,10 @@ public class MessageEncoder extends MessageToByteEncoder<InternalMessage> {
}
context.close();
}
// Effectively same result as one generated by MessageToByteEncoder<InternalMessage>
@Override
public final boolean acceptOutboundMessage(Object msg) throws Exception {
return msg instanceof InternalMessage;
}
}
......
......@@ -41,7 +41,6 @@ import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.apache.commons.pool.KeyedPoolableObjectFactory;
import org.apache.commons.pool.impl.GenericKeyedObjectPool;
import org.apache.felix.scr.annotations.Activate;
......@@ -383,7 +382,7 @@ public class NettyMessagingManager implements MessagingService {
}
// Start the client.
CompletableFuture<Channel> retFuture = new CompletableFuture<>();
ChannelFuture f = bootstrap.connect(ep.host().toString(), ep.port());
ChannelFuture f = bootstrap.connect(ep.host().toInetAddress(), ep.port());
f.addListener(future -> {
if (future.isSuccess()) {
......@@ -491,10 +490,13 @@ public class NettyMessagingManager implements MessagingService {
}
@ChannelHandler.Sharable
private class InboundMessageDispatcher extends SimpleChannelInboundHandler<InternalMessage> {
private class InboundMessageDispatcher extends SimpleChannelInboundHandler<Object> {
// Effectively SimpleChannelInboundHandler<InternalMessage>,
// had to specify <Object> to avoid Class Loader not being able to find some classes.
@Override
protected void channelRead0(ChannelHandlerContext ctx, InternalMessage message) throws Exception {
protected void channelRead0(ChannelHandlerContext ctx, Object rawMessage) throws Exception {
InternalMessage message = (InternalMessage) rawMessage;
try {
dispatchLocally(message);
} catch (RejectedExecutionException e) {
......@@ -507,7 +509,21 @@ public class NettyMessagingManager implements MessagingService {
log.error("Exception inside channel handling pipeline.", cause);
context.close();
}
/**
* Returns true if the given message should be handled.
*
* @param msg inbound message
* @return true if {@code msg} is {@link InternalMessage} instance.
*
* @see SimpleChannelInboundHandler#acceptInboundMessage(Object)
*/
@Override
public final boolean acceptInboundMessage(Object msg) {
return msg instanceof InternalMessage;
}
}
private void dispatchLocally(InternalMessage message) throws IOException {
if (message.preamble() != preamble) {
log.debug("Received {} with invalid preamble from {}", message.type(), message.sender());
......
......@@ -16,6 +16,7 @@
package org.onlab.packet;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.nio.ByteBuffer;
......@@ -142,6 +143,20 @@ public class IpAddress implements Comparable<IpAddress> {
}
/**
* Returns the IP address as InetAddress.
*
* @return InetAddress
*/
public InetAddress toInetAddress() {
try {
return InetAddress.getByAddress(octets);
} catch (UnknownHostException e) {
// Should never reach here
return null;
}
}
/**
* Computes the IP address byte length for a given IP version.
*
* @param version the IP version
......