1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.spi;
18
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import org.apache.logging.log4j.util.PropertiesUtil;
24
25
26
27
28
29
30
31 public class DefaultThreadContextMap implements ThreadContextMap {
32
33
34
35
36 public static final String INHERITABLE_MAP = "isThreadContextMapInheritable";
37
38 private final boolean useMap;
39 private final ThreadLocal<Map<String, String>> localMap;
40
41 public DefaultThreadContextMap(final boolean useMap) {
42 this.useMap = useMap;
43 this.localMap = createThreadLocalMap(useMap);
44 }
45
46
47
48 static ThreadLocal<Map<String, String>> createThreadLocalMap(final boolean isMapEnabled) {
49 final PropertiesUtil managerProps = PropertiesUtil.getProperties();
50 final boolean inheritable = managerProps.getBooleanProperty(INHERITABLE_MAP);
51 if (inheritable) {
52 return new InheritableThreadLocal<Map<String, String>>() {
53 @Override
54 protected Map<String, String> childValue(final Map<String, String> parentValue) {
55 return parentValue != null && isMapEnabled
56 ? Collections.unmodifiableMap(new HashMap<String, String>(parentValue))
57 : null;
58 }
59 };
60 }
61
62 return new ThreadLocal<Map<String, String>>();
63 }
64
65 @Override
66 public void put(final String key, final String value) {
67 if (!useMap) {
68 return;
69 }
70 Map<String, String> map = localMap.get();
71 map = map == null ? new HashMap<String, String>() : new HashMap<String, String>(map);
72 map.put(key, value);
73 localMap.set(Collections.unmodifiableMap(map));
74 }
75
76 @Override
77 public String get(final String key) {
78 final Map<String, String> map = localMap.get();
79 return map == null ? null : map.get(key);
80 }
81
82 @Override
83 public void remove(final String key) {
84 final Map<String, String> map = localMap.get();
85 if (map != null) {
86 final Map<String, String> copy = new HashMap<String, String>(map);
87 copy.remove(key);
88 localMap.set(Collections.unmodifiableMap(copy));
89 }
90 }
91
92 @Override
93 public void clear() {
94 localMap.remove();
95 }
96
97 @Override
98 public boolean containsKey(final String key) {
99 final Map<String, String> map = localMap.get();
100 return map != null && map.containsKey(key);
101 }
102
103 @Override
104 public Map<String, String> getCopy() {
105 final Map<String, String> map = localMap.get();
106 return map == null ? new HashMap<String, String>() : new HashMap<String, String>(map);
107 }
108
109 @Override
110 public Map<String, String> getImmutableMapOrNull() {
111 return localMap.get();
112 }
113
114 @Override
115 public boolean isEmpty() {
116 final Map<String, String> map = localMap.get();
117 return map == null || map.size() == 0;
118 }
119
120 @Override
121 public String toString() {
122 final Map<String, String> map = localMap.get();
123 return map == null ? "{}" : map.toString();
124 }
125
126 @Override
127 public int hashCode() {
128 final int prime = 31;
129 int result = 1;
130 final Map<String, String> map = this.localMap.get();
131 result = prime * result + ((map == null) ? 0 : map.hashCode());
132 result = prime * result + (this.useMap ? 1231 : 1237);
133 return result;
134 }
135
136 @Override
137 public boolean equals(final Object obj) {
138 if (this == obj) {
139 return true;
140 }
141 if (obj == null) {
142 return false;
143 }
144 if (obj instanceof DefaultThreadContextMap) {
145 final DefaultThreadContextMap other = (DefaultThreadContextMap) obj;
146 if (this.useMap != other.useMap) {
147 return false;
148 }
149 }
150 if (!(obj instanceof ThreadContextMap)) {
151 return false;
152 }
153 final ThreadContextMap other = (ThreadContextMap) obj;
154 final Map<String, String> map = this.localMap.get();
155 final Map<String, String> otherMap = other.getImmutableMapOrNull();
156 if (map == null) {
157 if (otherMap != null) {
158 return false;
159 }
160 } else if (!map.equals(otherMap)) {
161 return false;
162 }
163 return true;
164 }
165 }