Skip to content

Commit b60378e

Browse files
committed
Add thread storage implementation
1 parent 5dac489 commit b60378e

File tree

2 files changed

+152
-0
lines changed

2 files changed

+152
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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.utils;
17+
18+
import java.util.HashMap;
19+
import java.util.Map;
20+
import software.amazon.awssdk.annotations.SdkInternalApi;
21+
22+
/**
23+
* Utility for thread-local context storage.
24+
*/
25+
@SdkInternalApi
26+
public final class ThreadStorage {
27+
private static final ThreadLocal<Map<String, String>> storage = ThreadLocal.withInitial(HashMap::new);
28+
29+
private ThreadStorage() {}
30+
31+
public static void put(String key, String value) {
32+
storage.get().put(key, value);
33+
}
34+
35+
public static String get(String key) {
36+
return storage.get().get(key);
37+
}
38+
39+
public static String remove(String key) {
40+
return storage.get().remove(key);
41+
}
42+
43+
public static void clear() {
44+
storage.get().clear();
45+
}
46+
47+
public static boolean containsKey(String key) {
48+
return storage.get().containsKey(key);
49+
}
50+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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.utils;
17+
18+
import org.junit.jupiter.api.AfterEach;
19+
import org.junit.jupiter.api.Test;
20+
21+
import static org.assertj.core.api.Assertions.assertThat;
22+
23+
class ThreadStorageTest {
24+
25+
@AfterEach
26+
void cleanup() {
27+
ThreadStorage.clear();
28+
}
29+
30+
@Test
31+
void put_withValidKeyValue_shouldStoreValue() {
32+
ThreadStorage.put("test-key", "test-value");
33+
34+
assertThat(ThreadStorage.get("test-key")).isEqualTo("test-value");
35+
}
36+
37+
@Test
38+
void get_withNonExistentKey_shouldReturnNull() {
39+
assertThat(ThreadStorage.get("non-existent")).isNull();
40+
}
41+
42+
@Test
43+
void remove_withExistingKey_shouldRemoveAndReturnValue() {
44+
ThreadStorage.put("test-key", "test-value");
45+
46+
String removed = ThreadStorage.remove("test-key");
47+
48+
assertThat(removed).isEqualTo("test-value");
49+
assertThat(ThreadStorage.get("test-key")).isNull();
50+
}
51+
52+
@Test
53+
void put_withNullValue_shouldRemoveKey() {
54+
ThreadStorage.put("test-key", "test-value");
55+
ThreadStorage.put("test-key", null);
56+
57+
assertThat(ThreadStorage.get("test-key")).isNull();
58+
}
59+
60+
@Test
61+
void clear_withMultipleValues_shouldRemoveAllValues() {
62+
ThreadStorage.put("key1", "value1");
63+
ThreadStorage.put("key2", "value2");
64+
65+
ThreadStorage.clear();
66+
67+
assertThat(ThreadStorage.get("key1")).isNull();
68+
assertThat(ThreadStorage.get("key2")).isNull();
69+
}
70+
71+
@Test
72+
void containsKey_withExistingKey_shouldReturnTrue() {
73+
ThreadStorage.put("test-key", "test-value");
74+
75+
assertThat(ThreadStorage.containsKey("test-key")).isTrue();
76+
}
77+
78+
@Test
79+
void containsKey_withNonExistentKey_shouldReturnFalse() {
80+
assertThat(ThreadStorage.containsKey("non-existent")).isFalse();
81+
}
82+
83+
@Test
84+
void get_fromDifferentThread_shouldNotShareData() throws InterruptedException {
85+
ThreadStorage.put("shared-key", "main-thread-value");
86+
87+
Thread otherThread = new Thread(() -> {
88+
// Should not see main thread's value
89+
assertThat(ThreadStorage.get("shared-key")).isNull();
90+
91+
// Set own value
92+
ThreadStorage.put("shared-key", "other-thread-value");
93+
assertThat(ThreadStorage.get("shared-key")).isEqualTo("other-thread-value");
94+
});
95+
96+
otherThread.start();
97+
otherThread.join();
98+
99+
// Main thread should still have its own value
100+
assertThat(ThreadStorage.get("shared-key")).isEqualTo("main-thread-value");
101+
}
102+
}

0 commit comments

Comments
 (0)