Skip to content

Commit b679524

Browse files
authored
Merge pull request #1887 from dagnir/gh1886
Safely declare Netty AttributeKeys
2 parents d155ac8 + 96e67ec commit b679524

File tree

8 files changed

+79
-22
lines changed

8 files changed

+79
-22
lines changed

build-tools/src/main/resources/software/amazon/awssdk/checkstyle.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,14 @@
365365
<property name="ignoreComments" value="true"/>
366366
</module>
367367

368+
<!-- Checks that we don't use AttributeKey.newInstance directly -->
369+
<module name="Regexp">
370+
<property name="format" value="AttributeKey\.newInstance"/>
371+
<property name="illegalPattern" value="true"/>
372+
<property name="message" value="Use NettyUtils.getOrCreateAttributeKey to safely declare AttributeKeys"/>
373+
<property name="ignoreComments" value="true"/>
374+
</module>
375+
368376
<!-- Checks that we don't use plural enum names -->
369377
<module name="software.amazon.awssdk.buildtools.checkstyle.PluralEnumNames"/>
370378

http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/ChannelAttributeKey.java

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import software.amazon.awssdk.http.Protocol;
2727
import software.amazon.awssdk.http.nio.netty.internal.http2.Http2MultiplexedChannelPool;
2828
import software.amazon.awssdk.http.nio.netty.internal.http2.PingTracker;
29+
import software.amazon.awssdk.http.nio.netty.internal.utils.NettyUtils;
2930

3031
/**
3132
* Keys for attributes attached via {@link io.netty.channel.Channel#attr(AttributeKey)}.
@@ -36,70 +37,71 @@ public final class ChannelAttributeKey {
3637
/**
3738
* Future that when a protocol (http/1.1 or h2) has been selected.
3839
*/
39-
public static final AttributeKey<CompletableFuture<Protocol>> PROTOCOL_FUTURE = AttributeKey.newInstance(
40+
public static final AttributeKey<CompletableFuture<Protocol>> PROTOCOL_FUTURE = NettyUtils.getOrCreateAttributeKey(
4041
"aws.http.nio.netty.async.protocolFuture");
4142

4243
/**
4344
* Reference to {@link Http2MultiplexedChannelPool} which stores information about leased streams for a multiplexed
4445
* connection.
4546
*/
46-
public static final AttributeKey<Http2MultiplexedChannelPool> HTTP2_MULTIPLEXED_CHANNEL_POOL = AttributeKey.newInstance(
47-
"aws.http.nio.netty.async.http2MultiplexedChannelPool");
47+
public static final AttributeKey<Http2MultiplexedChannelPool> HTTP2_MULTIPLEXED_CHANNEL_POOL =
48+
NettyUtils.getOrCreateAttributeKey("aws.http.nio.netty.async.http2MultiplexedChannelPool");
4849

4950
public static final AttributeKey<PingTracker> PING_TRACKER =
50-
AttributeKey.newInstance("aws.http.nio.netty.async.h2.pingTracker");
51+
NettyUtils.getOrCreateAttributeKey("aws.http.nio.netty.async.h2.pingTracker");
5152

5253
public static final AttributeKey<Http2Connection> HTTP2_CONNECTION =
53-
AttributeKey.newInstance("aws.http.nio.netty.async.http2Connection");
54+
NettyUtils.getOrCreateAttributeKey("aws.http.nio.netty.async.http2Connection");
5455

5556
public static final AttributeKey<Integer> HTTP2_INITIAL_WINDOW_SIZE =
56-
AttributeKey.newInstance("aws.http.nio.netty.async.http2InitialWindowSize");
57+
NettyUtils.getOrCreateAttributeKey("aws.http.nio.netty.async.http2InitialWindowSize");
5758

5859
/**
5960
* Value of the MAX_CONCURRENT_STREAMS from the server's SETTING frame.
6061
*/
61-
public static final AttributeKey<Long> MAX_CONCURRENT_STREAMS = AttributeKey.newInstance(
62+
public static final AttributeKey<Long> MAX_CONCURRENT_STREAMS = NettyUtils.getOrCreateAttributeKey(
6263
"aws.http.nio.netty.async.maxConcurrentStreams");
6364

6465
/**
6566
* {@link AttributeKey} to keep track of whether we should close the connection after this request
6667
* has completed.
6768
*/
68-
static final AttributeKey<Boolean> KEEP_ALIVE = AttributeKey.newInstance("aws.http.nio.netty.async.keepAlive");
69+
static final AttributeKey<Boolean> KEEP_ALIVE = NettyUtils.getOrCreateAttributeKey("aws.http.nio.netty.async.keepAlive");
6970

7071
/**
7172
* Attribute key for {@link RequestContext}.
7273
*/
73-
static final AttributeKey<RequestContext> REQUEST_CONTEXT_KEY = AttributeKey.newInstance(
74+
static final AttributeKey<RequestContext> REQUEST_CONTEXT_KEY = NettyUtils.getOrCreateAttributeKey(
7475
"aws.http.nio.netty.async.requestContext");
7576

76-
static final AttributeKey<Subscriber<? super ByteBuffer>> SUBSCRIBER_KEY = AttributeKey.newInstance(
77+
static final AttributeKey<Subscriber<? super ByteBuffer>> SUBSCRIBER_KEY = NettyUtils.getOrCreateAttributeKey(
7778
"aws.http.nio.netty.async.subscriber");
7879

79-
static final AttributeKey<Boolean> RESPONSE_COMPLETE_KEY = AttributeKey.newInstance(
80+
static final AttributeKey<Boolean> RESPONSE_COMPLETE_KEY = NettyUtils.getOrCreateAttributeKey(
8081
"aws.http.nio.netty.async.responseComplete");
8182

8283
/**
8384
* {@link AttributeKey} to keep track of whether we have received the {@link LastHttpContent}.
8485
*/
85-
static final AttributeKey<Boolean> LAST_HTTP_CONTENT_RECEIVED_KEY = AttributeKey.newInstance(
86+
static final AttributeKey<Boolean> LAST_HTTP_CONTENT_RECEIVED_KEY = NettyUtils.getOrCreateAttributeKey(
8687
"aws.http.nio.netty.async.lastHttpContentReceived");
8788

88-
static final AttributeKey<CompletableFuture<Void>> EXECUTE_FUTURE_KEY = AttributeKey.newInstance(
89+
static final AttributeKey<CompletableFuture<Void>> EXECUTE_FUTURE_KEY = NettyUtils.getOrCreateAttributeKey(
8990
"aws.http.nio.netty.async.executeFuture");
9091

91-
static final AttributeKey<Long> EXECUTION_ID_KEY = AttributeKey.newInstance(
92+
static final AttributeKey<Long> EXECUTION_ID_KEY = NettyUtils.getOrCreateAttributeKey(
9293
"aws.http.nio.netty.async.executionId");
9394

9495
/**
9596
* Whether the channel is still in use
9697
*/
97-
static final AttributeKey<Boolean> IN_USE = AttributeKey.newInstance("aws.http.nio.netty.async.inUse");
98+
static final AttributeKey<Boolean> IN_USE = NettyUtils.getOrCreateAttributeKey("aws.http.nio.netty.async.inUse");
9899

99100
/**
100101
* Whether the channel should be closed once it is released.
101102
*/
102-
static final AttributeKey<Boolean> CLOSE_ON_RELEASE = AttributeKey.newInstance("aws.http.nio.netty.async.closeOnRelease");
103+
static final AttributeKey<Boolean> CLOSE_ON_RELEASE = NettyUtils.getOrCreateAttributeKey(
104+
"aws.http.nio.netty.async.closeOnRelease");
103105

104106
private ChannelAttributeKey() {
105107
}

http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/Http1TunnelConnectionPool.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.net.URI;
3030
import software.amazon.awssdk.annotations.SdkInternalApi;
3131
import software.amazon.awssdk.annotations.SdkTestInternalApi;
32+
import software.amazon.awssdk.http.nio.netty.internal.utils.NettyUtils;
3233
import software.amazon.awssdk.utils.Logger;
3334
import software.amazon.awssdk.utils.StringUtils;
3435

@@ -37,7 +38,7 @@
3738
*/
3839
@SdkInternalApi
3940
public class Http1TunnelConnectionPool implements ChannelPool {
40-
static final AttributeKey<Boolean> TUNNEL_ESTABLISHED_KEY = AttributeKey.newInstance(
41+
static final AttributeKey<Boolean> TUNNEL_ESTABLISHED_KEY = NettyUtils.getOrCreateAttributeKey(
4142
"aws.http.nio.netty.async.Http1TunnelConnectionPool.tunnelEstablished");
4243

4344
private static final Logger log = Logger.loggerFor(Http1TunnelConnectionPool.class);

http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/ReleaseOnceChannelPool.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.concurrent.atomic.AtomicBoolean;
2727
import software.amazon.awssdk.annotations.SdkInternalApi;
2828
import software.amazon.awssdk.http.nio.netty.internal.http2.Http2MultiplexedChannelPool;
29+
import software.amazon.awssdk.http.nio.netty.internal.utils.NettyUtils;
2930

3031
/**
3132
* Wrapper around a {@link ChannelPool} to protect it from having the same channel released twice. This can
@@ -35,7 +36,8 @@
3536
@SdkInternalApi
3637
public class ReleaseOnceChannelPool implements ChannelPool {
3738

38-
private static final AttributeKey<AtomicBoolean> IS_RELEASED = AttributeKey.newInstance("isReleased");
39+
private static final AttributeKey<AtomicBoolean> IS_RELEASED = NettyUtils.getOrCreateAttributeKey(
40+
"software.amazon.awssdk.http.nio.netty.internal.http2.ReleaseOnceChannelPool.isReleased");
3941

4042
private final ChannelPool delegate;
4143

http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/http2/Http2MultiplexedChannelPool.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import software.amazon.awssdk.http.Protocol;
5151
import software.amazon.awssdk.http.nio.netty.internal.ChannelAttributeKey;
5252
import software.amazon.awssdk.http.nio.netty.internal.utils.BetterFixedChannelPool;
53+
import software.amazon.awssdk.http.nio.netty.internal.utils.NettyUtils;
5354
import software.amazon.awssdk.utils.Logger;
5455
import software.amazon.awssdk.utils.Validate;
5556

@@ -72,13 +73,13 @@ public class Http2MultiplexedChannelPool implements ChannelPool {
7273
/**
7374
* Reference to the {@link MultiplexedChannelRecord} on a channel.
7475
*/
75-
private static final AttributeKey<MultiplexedChannelRecord> MULTIPLEXED_CHANNEL = AttributeKey.newInstance(
76-
"software.amazon.awssdk.http.nio.netty.internal.http2.Http2MultiplexedChannelPool.MULTIPLEXED_CHANNEL");
76+
private static final AttributeKey<MultiplexedChannelRecord> MULTIPLEXED_CHANNEL = NettyUtils.getOrCreateAttributeKey(
77+
"software.amazon.awssdk.http.nio.netty.internal.http2.Http2MultiplexedChannelPool.MULTIPLEXED_CHANNEL");
7778

7879
/**
7980
* Whether a parent channel has been released yet. This guards against double-releasing to the delegate connection pool.
8081
*/
81-
private static final AttributeKey<Boolean> RELEASED = AttributeKey.newInstance(
82+
private static final AttributeKey<Boolean> RELEASED = NettyUtils.getOrCreateAttributeKey(
8283
"software.amazon.awssdk.http.nio.netty.internal.http2.Http2MultiplexedChannelPool.RELEASED");
8384

8485
private final ChannelPool connectionPool;

http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/utils/NettyUtils.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package software.amazon.awssdk.http.nio.netty.internal.utils;
1717

1818
import io.netty.channel.EventLoop;
19+
import io.netty.util.AttributeKey;
1920
import io.netty.util.concurrent.EventExecutor;
2021
import io.netty.util.concurrent.Future;
2122
import io.netty.util.concurrent.GenericFutureListener;
@@ -160,4 +161,16 @@ public static void warnIfNotInEventLoop(EventLoop loop) {
160161
log.warn(() -> "Execution is happening outside of the expected event loop.", exception);
161162
}
162163
}
164+
165+
/**
166+
* @return an {@code AttributeKey} for {@code attr}. This returns an existing instance if it was previously created.
167+
*/
168+
public static <T> AttributeKey<T> getOrCreateAttributeKey(String attr) {
169+
if (AttributeKey.exists(attr)) {
170+
return AttributeKey.valueOf(attr);
171+
}
172+
//CHECKSTYLE:OFF - This is the only place allowed to call AttributeKey.newInstance()
173+
return AttributeKey.newInstance(attr);
174+
//CHECKSTYLE:ON
175+
}
163176
}

http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/internal/utils/OrderedWriteChannelHandlerContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
@SdkInternalApi
3232
public class OrderedWriteChannelHandlerContext extends DelegatingChannelHandlerContext {
3333
private static final AttributeKey<Void> ORDERED =
34-
AttributeKey.newInstance("aws.http.nio.netty.async.OrderedWriteChannelHandlerContext.ORDERED");
34+
NettyUtils.getOrCreateAttributeKey("aws.http.nio.netty.async.OrderedWriteChannelHandlerContext.ORDERED");
3535

3636
private OrderedWriteChannelHandlerContext(ChannelHandlerContext delegate) {
3737
super(delegate);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.http.nio.netty.internal.utils;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
20+
import io.netty.util.AttributeKey;
21+
import org.junit.Test;
22+
23+
public class NettyUtilsTest {
24+
@Test
25+
public void testGetOrCreateAttributeKey_calledTwiceWithSameName_returnsSameInstance() {
26+
String attr = "NettyUtilsTest.Foo";
27+
AttributeKey<String> fooAttr = NettyUtils.getOrCreateAttributeKey(attr);
28+
assertThat(NettyUtils.getOrCreateAttributeKey(attr)).isSameAs(fooAttr);
29+
}
30+
}

0 commit comments

Comments
 (0)