- * There are three ways to create a new instance. + * There are four ways to create a new instance. * *
@@ -76,6 +81,16 @@ public final class SdkEventLoopGroup { this.datagramChannelFactory = ChannelResolver.resolveDatagramChannelFactory(eventLoopGroup); } + SdkEventLoopGroup(EventLoopGroup eventLoopGroup, ChannelFactory extends Channel> socketChannelFactory, + ChannelFactory extends DatagramChannel> datagramChannelFactory) { + Validate.paramNotNull(eventLoopGroup, "eventLoopGroup"); + Validate.paramNotNull(socketChannelFactory, "socketChannelFactory"); + Validate.paramNotNull(datagramChannelFactory, "datagramChannelFactory"); + this.eventLoopGroup = eventLoopGroup; + this.channelFactory = socketChannelFactory; + this.datagramChannelFactory = datagramChannelFactory; + } + /** * Create an instance of {@link SdkEventLoopGroup} from the builder */ @@ -107,15 +122,30 @@ public ChannelFactory extends DatagramChannel> datagramChannelFactory() { } /** - * Creates a new instance of SdkEventLoopGroup with {@link EventLoopGroup} and {@link ChannelFactory} + * Creates a new instance of SdkEventLoopGroup with {@link EventLoopGroup} and socket {@link ChannelFactory} * to be used with {@link NettyNioAsyncHttpClient}. * * @param eventLoopGroup the EventLoopGroup to be used - * @param channelFactory the channel factor to be used + * @param socketChannelFactory the socket channel factory to be used + * @return a new instance of SdkEventLoopGroup + */ + public static SdkEventLoopGroup create(EventLoopGroup eventLoopGroup, + ChannelFactory extends Channel> socketChannelFactory) { + return new SdkEventLoopGroup(eventLoopGroup, socketChannelFactory); + } + + /** + * Creates a new instance of SdkEventLoopGroup with {@link EventLoopGroup}, and socket and datagram + * {@link ChannelFactory}'s to be used with {@link NettyNioAsyncHttpClient}. + * + * @param eventLoopGroup the EventLoopGroup to be used + * @param socketChannelFactory the socket channel factory to be used + * @param datagramChannelFactory the datagram channel factory to be used * @return a new instance of SdkEventLoopGroup */ - public static SdkEventLoopGroup create(EventLoopGroup eventLoopGroup, ChannelFactory extends Channel> channelFactory) { - return new SdkEventLoopGroup(eventLoopGroup, channelFactory); + public static SdkEventLoopGroup create(EventLoopGroup eventLoopGroup, ChannelFactory extends Channel> socketChannelFactory, + ChannelFactory extends DatagramChannel> datagramChannelFactory) { + return new SdkEventLoopGroup(eventLoopGroup, socketChannelFactory, datagramChannelFactory); } /** @@ -125,6 +155,17 @@ public static SdkEventLoopGroup create(EventLoopGroup eventLoopGroup, ChannelFac * {@link ChannelFactory} will be resolved based on the type of {@link EventLoopGroup} provided. IllegalArgumentException will * be thrown for any unknown EventLoopGroup type. * + *
+ * Special handling for {@link MultiThreadIoEventLoopGroup}: + * When a {@link MultiThreadIoEventLoopGroup} is provided (not the deprecated transport-specific event loop groups like + * {@link NioEventLoopGroup}) the SDK cannot determine which transport type was configured and will default to using + * {@link NioSocketChannel} and {@link NioDatagramChannel}. + * + *
+ * To use {@link MultiThreadIoEventLoopGroup} with non-NIO transports (such as Epoll or KQueue),
+ * use {@link #create(EventLoopGroup, ChannelFactory, ChannelFactory)} and explicitly specify
+ * the desired socket and datagram channel factories.
+ *
* @param eventLoopGroup the EventLoopGroup to be used
* @return a new instance of SdkEventLoopGroup
*/
@@ -142,7 +183,7 @@ private EventLoopGroup resolveEventLoopGroup(DefaultBuilder builder) {
.orElseGet(() -> new ThreadFactoryBuilder()
.threadNamePrefix("aws-java-sdk-NettyEventLoop")
.build());
- return new NioEventLoopGroup(numThreads, threadFactory);
+ return new MultiThreadIoEventLoopGroup(numThreads, threadFactory, NioIoHandler.newFactory());
/*
Need to investigate why epoll is raising channel inactive after successful response that causes
problems with retries.
diff --git a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/utils/ChannelResolver.java b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/utils/ChannelResolver.java
index 8770d683a679..05c21d4e9cec 100644
--- a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/utils/ChannelResolver.java
+++ b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/utils/ChannelResolver.java
@@ -20,6 +20,7 @@
import io.netty.channel.Channel;
import io.netty.channel.ChannelFactory;
import io.netty.channel.EventLoopGroup;
+import io.netty.channel.MultiThreadIoEventLoopGroup;
import io.netty.channel.ReflectiveChannelFactory;
import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollEventLoopGroup;
@@ -75,11 +76,17 @@ public static ChannelFactory extends Channel> resolveSocketChannelFactory(Even
}
String socketFqcn = KNOWN_EL_GROUPS_SOCKET_CHANNELS.get(eventLoopGroup.getClass().getName());
- if (socketFqcn == null) {
- throw new IllegalArgumentException("Unknown event loop group : " + eventLoopGroup.getClass());
+ if (socketFqcn != null) {
+ return invokeSafely(() -> new ReflectiveChannelFactory(Class.forName(socketFqcn)));
}
- return invokeSafely(() -> new ReflectiveChannelFactory(Class.forName(socketFqcn)));
+ // The old deprecated transport-specific event loop groups all extend MultiThreadIoEventLoopGroup, so we have to do
+ // this check last. It is not possible to determine the type of transport factory so we will default to Nio.
+ if (eventLoopGroup instanceof MultiThreadIoEventLoopGroup) {
+ return NioSocketChannel::new;
+ }
+
+ throw new IllegalArgumentException("Unknown event loop group : " + eventLoopGroup.getClass());
}
/**
@@ -103,10 +110,16 @@ public static ChannelFactory extends DatagramChannel> resolveDatagramChannelFa
}
String datagramFqcn = KNOWN_EL_GROUPS_DATAGRAM_CHANNELS.get(eventLoopGroup.getClass().getName());
- if (datagramFqcn == null) {
- throw new IllegalArgumentException("Unknown event loop group : " + eventLoopGroup.getClass());
+ if (datagramFqcn != null) {
+ return invokeSafely(() -> new ReflectiveChannelFactory(Class.forName(datagramFqcn)));
+ }
+
+ // The old deprecated transport-specific event loop groups all extend MultiThreadIoEventLoopGroup, so we have to do
+ // this check last. It is not possible to determine the type of transport factory so we will default to Nio.
+ if (eventLoopGroup instanceof MultiThreadIoEventLoopGroup) {
+ return NioDatagramChannel::new;
}
- return invokeSafely(() -> new ReflectiveChannelFactory(Class.forName(datagramFqcn)));
+ throw new IllegalArgumentException("Unknown event loop group : " + eventLoopGroup.getClass());
}
}
diff --git a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/utils/NettyUtils.java b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/utils/NettyUtils.java
index 6a9d0eedb682..f832c0f90751 100644
--- a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/utils/NettyUtils.java
+++ b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/utils/NettyUtils.java
@@ -336,7 +336,6 @@ public static SslHandler newSslHandler(SslContext sslContext, ByteBufAllocator a
*/
private static void configureSslEngine(SSLEngine sslEngine) {
SSLParameters sslParameters = sslEngine.getSSLParameters();
- sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
sslEngine.setSSLParameters(sslParameters);
}
diff --git a/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/SdkEventLoopGroupTest.java b/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/SdkEventLoopGroupTest.java
index bb2598345cff..7f26b5ebfdc0 100644
--- a/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/SdkEventLoopGroupTest.java
+++ b/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/SdkEventLoopGroupTest.java
@@ -16,18 +16,23 @@
package software.amazon.awssdk.http.nio.netty;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import io.netty.channel.DefaultEventLoopGroup;
+import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollDatagramChannel;
-import io.netty.channel.epoll.EpollEventLoopGroup;
+import io.netty.channel.epoll.EpollIoHandler;
import io.netty.channel.epoll.EpollSocketChannel;
+import io.netty.channel.MultiThreadIoEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.nio.NioIoHandler;
import io.netty.channel.oio.OioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.channel.socket.oio.OioDatagramChannel;
import io.netty.channel.socket.oio.OioSocketChannel;
-import org.junit.Test;
+import org.junit.jupiter.api.Assumptions;
+import org.junit.jupiter.api.Test;
public class SdkEventLoopGroupTest {
@@ -64,8 +69,42 @@ public void notProvidingChannelFactory_channelFactoryResolved() {
assertThat(sdkEventLoopGroup.datagramChannelFactory().newChannel()).isInstanceOf(NioDatagramChannel.class);
}
- @Test(expected = IllegalArgumentException.class)
+ @Test
+ public void multiThreadIoEventLoopGroup_nioIoHandler_withoutChannelFactory() {
+ SdkEventLoopGroup sdkEventLoopGroup =
+ SdkEventLoopGroup.create(new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory()));
+
+ assertThat(sdkEventLoopGroup.channelFactory().newChannel()).isInstanceOf(NioSocketChannel.class);
+ assertThat(sdkEventLoopGroup.datagramChannelFactory().newChannel()).isInstanceOf(NioDatagramChannel.class);
+ }
+
+ @Test
+ public void multiThreadIoEventLoopGroupWithNonNioIoHandler_withoutChannelFactory_createsNioChannels() {
+ Assumptions.assumeTrue(Epoll.isAvailable());
+
+ SdkEventLoopGroup sdkEventLoopGroup =
+ SdkEventLoopGroup.create(new MultiThreadIoEventLoopGroup(EpollIoHandler.newFactory()));
+
+ assertThat(sdkEventLoopGroup.channelFactory().newChannel()).isInstanceOf(NioSocketChannel.class);
+ assertThat(sdkEventLoopGroup.datagramChannelFactory().newChannel()).isInstanceOf(NioDatagramChannel.class);
+ }
+
+ @Test
+ public void multiThreadIoEventLoopGroupWithNonNioIoHandler_withChannelsFactories_properlySetsChannelTypes() {
+ Assumptions.assumeTrue(Epoll.isAvailable());
+
+ SdkEventLoopGroup sdkEventLoopGroup =
+ SdkEventLoopGroup.create(new MultiThreadIoEventLoopGroup(EpollIoHandler.newFactory()),
+ EpollSocketChannel::new,
+ EpollDatagramChannel::new);
+ assertThat(sdkEventLoopGroup.channelFactory()).isNotNull();
+ assertThat(sdkEventLoopGroup.channelFactory().newChannel()).isInstanceOf(EpollSocketChannel.class);
+ assertThat(sdkEventLoopGroup.datagramChannelFactory().newChannel()).isInstanceOf(EpollDatagramChannel.class);
+ assertThat(sdkEventLoopGroup.eventLoopGroup()).isNotNull();
+ }
+
+ @Test
public void notProvidingChannelFactory_unknownEventLoopGroup() {
- SdkEventLoopGroup.create(new DefaultEventLoopGroup());
+ assertThrows(IllegalArgumentException.class, () -> SdkEventLoopGroup.create(new DefaultEventLoopGroup()));
}
}
diff --git a/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/fault/ServerConnectivityErrorMessageTest.java b/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/fault/ServerConnectivityErrorMessageTest.java
index 70857614033b..e7258a9d63f8 100644
--- a/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/fault/ServerConnectivityErrorMessageTest.java
+++ b/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/fault/ServerConnectivityErrorMessageTest.java
@@ -29,8 +29,10 @@
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.MultiThreadIoEventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
-import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.nio.NioIoHandler;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.DefaultHttpContent;
@@ -312,7 +314,7 @@ public RequestParams build(){
}
private static class Server extends ChannelInitializer