diff --git a/build-tools/src/main/resources/software/amazon/awssdk/checkstyle.xml b/build-tools/src/main/resources/software/amazon/awssdk/checkstyle.xml index 1d42ef9f8f7f..05001c3fba7b 100644 --- a/build-tools/src/main/resources/software/amazon/awssdk/checkstyle.xml +++ b/build-tools/src/main/resources/software/amazon/awssdk/checkstyle.xml @@ -365,6 +365,14 @@ + + + + + + + + diff --git a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/ChannelAttributeKey.java b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/ChannelAttributeKey.java index f2feca135ffa..3a2b9e51d31b 100644 --- a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/ChannelAttributeKey.java +++ b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/ChannelAttributeKey.java @@ -26,6 +26,7 @@ import software.amazon.awssdk.http.Protocol; import software.amazon.awssdk.http.nio.netty.internal.http2.Http2MultiplexedChannelPool; import software.amazon.awssdk.http.nio.netty.internal.http2.PingTracker; +import software.amazon.awssdk.http.nio.netty.internal.utils.NettyUtils; /** * Keys for attributes attached via {@link io.netty.channel.Channel#attr(AttributeKey)}. @@ -36,70 +37,71 @@ public final class ChannelAttributeKey { /** * Future that when a protocol (http/1.1 or h2) has been selected. */ - public static final AttributeKey> PROTOCOL_FUTURE = AttributeKey.newInstance( + public static final AttributeKey> PROTOCOL_FUTURE = NettyUtils.getOrCreateAttributeKey( "aws.http.nio.netty.async.protocolFuture"); /** * Reference to {@link Http2MultiplexedChannelPool} which stores information about leased streams for a multiplexed * connection. */ - public static final AttributeKey HTTP2_MULTIPLEXED_CHANNEL_POOL = AttributeKey.newInstance( - "aws.http.nio.netty.async.http2MultiplexedChannelPool"); + public static final AttributeKey HTTP2_MULTIPLEXED_CHANNEL_POOL = + NettyUtils.getOrCreateAttributeKey("aws.http.nio.netty.async.http2MultiplexedChannelPool"); public static final AttributeKey PING_TRACKER = - AttributeKey.newInstance("aws.http.nio.netty.async.h2.pingTracker"); + NettyUtils.getOrCreateAttributeKey("aws.http.nio.netty.async.h2.pingTracker"); public static final AttributeKey HTTP2_CONNECTION = - AttributeKey.newInstance("aws.http.nio.netty.async.http2Connection"); + NettyUtils.getOrCreateAttributeKey("aws.http.nio.netty.async.http2Connection"); public static final AttributeKey HTTP2_INITIAL_WINDOW_SIZE = - AttributeKey.newInstance("aws.http.nio.netty.async.http2InitialWindowSize"); + NettyUtils.getOrCreateAttributeKey("aws.http.nio.netty.async.http2InitialWindowSize"); /** * Value of the MAX_CONCURRENT_STREAMS from the server's SETTING frame. */ - public static final AttributeKey MAX_CONCURRENT_STREAMS = AttributeKey.newInstance( + public static final AttributeKey MAX_CONCURRENT_STREAMS = NettyUtils.getOrCreateAttributeKey( "aws.http.nio.netty.async.maxConcurrentStreams"); /** * {@link AttributeKey} to keep track of whether we should close the connection after this request * has completed. */ - static final AttributeKey KEEP_ALIVE = AttributeKey.newInstance("aws.http.nio.netty.async.keepAlive"); + static final AttributeKey KEEP_ALIVE = NettyUtils.getOrCreateAttributeKey("aws.http.nio.netty.async.keepAlive"); /** * Attribute key for {@link RequestContext}. */ - static final AttributeKey REQUEST_CONTEXT_KEY = AttributeKey.newInstance( + static final AttributeKey REQUEST_CONTEXT_KEY = NettyUtils.getOrCreateAttributeKey( "aws.http.nio.netty.async.requestContext"); - static final AttributeKey> SUBSCRIBER_KEY = AttributeKey.newInstance( + static final AttributeKey> SUBSCRIBER_KEY = NettyUtils.getOrCreateAttributeKey( "aws.http.nio.netty.async.subscriber"); - static final AttributeKey RESPONSE_COMPLETE_KEY = AttributeKey.newInstance( + static final AttributeKey RESPONSE_COMPLETE_KEY = NettyUtils.getOrCreateAttributeKey( "aws.http.nio.netty.async.responseComplete"); /** * {@link AttributeKey} to keep track of whether we have received the {@link LastHttpContent}. */ - static final AttributeKey LAST_HTTP_CONTENT_RECEIVED_KEY = AttributeKey.newInstance( + static final AttributeKey LAST_HTTP_CONTENT_RECEIVED_KEY = NettyUtils.getOrCreateAttributeKey( "aws.http.nio.netty.async.lastHttpContentReceived"); - static final AttributeKey> EXECUTE_FUTURE_KEY = AttributeKey.newInstance( + static final AttributeKey> EXECUTE_FUTURE_KEY = NettyUtils.getOrCreateAttributeKey( "aws.http.nio.netty.async.executeFuture"); - static final AttributeKey EXECUTION_ID_KEY = AttributeKey.newInstance( + static final AttributeKey EXECUTION_ID_KEY = NettyUtils.getOrCreateAttributeKey( "aws.http.nio.netty.async.executionId"); /** * Whether the channel is still in use */ - static final AttributeKey IN_USE = AttributeKey.newInstance("aws.http.nio.netty.async.inUse"); + static final AttributeKey IN_USE = NettyUtils.getOrCreateAttributeKey("aws.http.nio.netty.async.inUse"); /** * Whether the channel should be closed once it is released. */ - static final AttributeKey CLOSE_ON_RELEASE = AttributeKey.newInstance("aws.http.nio.netty.async.closeOnRelease"); + static final AttributeKey CLOSE_ON_RELEASE = NettyUtils.getOrCreateAttributeKey( + "aws.http.nio.netty.async.closeOnRelease"); private ChannelAttributeKey() { } diff --git a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/Http1TunnelConnectionPool.java b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/Http1TunnelConnectionPool.java index b2a416c0cafe..f687f7052c3d 100644 --- a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/Http1TunnelConnectionPool.java +++ b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/Http1TunnelConnectionPool.java @@ -29,6 +29,7 @@ import java.net.URI; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.annotations.SdkTestInternalApi; +import software.amazon.awssdk.http.nio.netty.internal.utils.NettyUtils; import software.amazon.awssdk.utils.Logger; import software.amazon.awssdk.utils.StringUtils; @@ -37,7 +38,7 @@ */ @SdkInternalApi public class Http1TunnelConnectionPool implements ChannelPool { - static final AttributeKey TUNNEL_ESTABLISHED_KEY = AttributeKey.newInstance( + static final AttributeKey TUNNEL_ESTABLISHED_KEY = NettyUtils.getOrCreateAttributeKey( "aws.http.nio.netty.async.Http1TunnelConnectionPool.tunnelEstablished"); private static final Logger log = Logger.loggerFor(Http1TunnelConnectionPool.class); diff --git a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/ReleaseOnceChannelPool.java b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/ReleaseOnceChannelPool.java index e0fb07427704..dd9b92517cf6 100644 --- a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/ReleaseOnceChannelPool.java +++ b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/ReleaseOnceChannelPool.java @@ -26,6 +26,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.http.nio.netty.internal.http2.Http2MultiplexedChannelPool; +import software.amazon.awssdk.http.nio.netty.internal.utils.NettyUtils; /** * Wrapper around a {@link ChannelPool} to protect it from having the same channel released twice. This can @@ -35,7 +36,8 @@ @SdkInternalApi public class ReleaseOnceChannelPool implements ChannelPool { - private static final AttributeKey IS_RELEASED = AttributeKey.newInstance("isReleased"); + private static final AttributeKey IS_RELEASED = NettyUtils.getOrCreateAttributeKey( + "software.amazon.awssdk.http.nio.netty.internal.http2.ReleaseOnceChannelPool.isReleased"); private final ChannelPool delegate; diff --git a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/http2/Http2MultiplexedChannelPool.java b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/http2/Http2MultiplexedChannelPool.java index 6118ba0b1230..bfdfee4c26e0 100644 --- a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/http2/Http2MultiplexedChannelPool.java +++ b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/http2/Http2MultiplexedChannelPool.java @@ -50,6 +50,7 @@ import software.amazon.awssdk.http.Protocol; import software.amazon.awssdk.http.nio.netty.internal.ChannelAttributeKey; import software.amazon.awssdk.http.nio.netty.internal.utils.BetterFixedChannelPool; +import software.amazon.awssdk.http.nio.netty.internal.utils.NettyUtils; import software.amazon.awssdk.utils.Logger; import software.amazon.awssdk.utils.Validate; @@ -72,13 +73,13 @@ public class Http2MultiplexedChannelPool implements ChannelPool { /** * Reference to the {@link MultiplexedChannelRecord} on a channel. */ - private static final AttributeKey MULTIPLEXED_CHANNEL = AttributeKey.newInstance( - "software.amazon.awssdk.http.nio.netty.internal.http2.Http2MultiplexedChannelPool.MULTIPLEXED_CHANNEL"); + private static final AttributeKey MULTIPLEXED_CHANNEL = NettyUtils.getOrCreateAttributeKey( + "software.amazon.awssdk.http.nio.netty.internal.http2.Http2MultiplexedChannelPool.MULTIPLEXED_CHANNEL"); /** * Whether a parent channel has been released yet. This guards against double-releasing to the delegate connection pool. */ - private static final AttributeKey RELEASED = AttributeKey.newInstance( + private static final AttributeKey RELEASED = NettyUtils.getOrCreateAttributeKey( "software.amazon.awssdk.http.nio.netty.internal.http2.Http2MultiplexedChannelPool.RELEASED"); private final ChannelPool connectionPool; 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 4d0b20b4a128..584bdc635f8e 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 @@ -16,6 +16,7 @@ package software.amazon.awssdk.http.nio.netty.internal.utils; import io.netty.channel.EventLoop; +import io.netty.util.AttributeKey; import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; @@ -160,4 +161,16 @@ public static void warnIfNotInEventLoop(EventLoop loop) { log.warn(() -> "Execution is happening outside of the expected event loop.", exception); } } + + /** + * @return an {@code AttributeKey} for {@code attr}. This returns an existing instance if it was previously created. + */ + public static AttributeKey getOrCreateAttributeKey(String attr) { + if (AttributeKey.exists(attr)) { + return AttributeKey.valueOf(attr); + } + //CHECKSTYLE:OFF - This is the only place allowed to call AttributeKey.newInstance() + return AttributeKey.newInstance(attr); + //CHECKSTYLE:ON + } } diff --git a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/utils/OrderedWriteChannelHandlerContext.java b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/utils/OrderedWriteChannelHandlerContext.java index 9e06a565e8e2..2a27c2dd32f0 100644 --- a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/utils/OrderedWriteChannelHandlerContext.java +++ b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/utils/OrderedWriteChannelHandlerContext.java @@ -31,7 +31,7 @@ @SdkInternalApi public class OrderedWriteChannelHandlerContext extends DelegatingChannelHandlerContext { private static final AttributeKey ORDERED = - AttributeKey.newInstance("aws.http.nio.netty.async.OrderedWriteChannelHandlerContext.ORDERED"); + NettyUtils.getOrCreateAttributeKey("aws.http.nio.netty.async.OrderedWriteChannelHandlerContext.ORDERED"); private OrderedWriteChannelHandlerContext(ChannelHandlerContext delegate) { super(delegate); diff --git a/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/internal/utils/NettyUtilsTest.java b/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/internal/utils/NettyUtilsTest.java new file mode 100644 index 000000000000..680057886174 --- /dev/null +++ b/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/internal/utils/NettyUtilsTest.java @@ -0,0 +1,30 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.http.nio.netty.internal.utils; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.netty.util.AttributeKey; +import org.junit.Test; + +public class NettyUtilsTest { + @Test + public void testGetOrCreateAttributeKey_calledTwiceWithSameName_returnsSameInstance() { + String attr = "NettyUtilsTest.Foo"; + AttributeKey fooAttr = NettyUtils.getOrCreateAttributeKey(attr); + assertThat(NettyUtils.getOrCreateAttributeKey(attr)).isSameAs(fooAttr); + } +}