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.Collection;
20 import java.util.Collections;
21 import java.util.Iterator;
22 import java.util.List;
23
24 import org.apache.logging.log4j.ThreadContext.ContextStack;
25 import org.apache.logging.log4j.util.StringBuilderFormattable;
26 import org.apache.logging.log4j.util.StringBuilders;
27 import org.apache.logging.log4j.util.Strings;
28
29
30
31
32
33 public class DefaultThreadContextStack implements ThreadContextStack, StringBuilderFormattable {
34
35 private static final long serialVersionUID = 5050501L;
36
37 private static final ThreadLocal<MutableThreadContextStack> STACK = new ThreadLocal<>();
38
39 private final boolean useStack;
40
41 public DefaultThreadContextStack(final boolean useStack) {
42 this.useStack = useStack;
43 }
44
45 private MutableThreadContextStack getNonNullStackCopy() {
46 final MutableThreadContextStack values = STACK.get();
47 return (MutableThreadContextStack) (values == null ? new MutableThreadContextStack() : values.copy());
48 }
49
50 @Override
51 public boolean add(final String s) {
52 if (!useStack) {
53 return false;
54 }
55 final MutableThreadContextStack copy = getNonNullStackCopy();
56 copy.add(s);
57 copy.freeze();
58 STACK.set(copy);
59 return true;
60 }
61
62 @Override
63 public boolean addAll(final Collection<? extends String> strings) {
64 if (!useStack || strings.isEmpty()) {
65 return false;
66 }
67 final MutableThreadContextStack copy = getNonNullStackCopy();
68 copy.addAll(strings);
69 copy.freeze();
70 STACK.set(copy);
71 return true;
72 }
73
74 @Override
75 public List<String> asList() {
76 final MutableThreadContextStack values = STACK.get();
77 if (values == null) {
78 return Collections.emptyList();
79 }
80 return values.asList();
81 }
82
83 @Override
84 public void clear() {
85 STACK.remove();
86 }
87
88 @Override
89 public boolean contains(final Object o) {
90 final MutableThreadContextStack values = STACK.get();
91 return values != null && values.contains(o);
92 }
93
94 @Override
95 public boolean containsAll(final Collection<?> objects) {
96 if (objects.isEmpty()) {
97 return true;
98
99 }
100 final MutableThreadContextStack values = STACK.get();
101 return values != null && values.containsAll(objects);
102 }
103
104 @Override
105 public ThreadContextStack copy() {
106 MutableThreadContextStack values = null;
107 if (!useStack || (values = STACK.get()) == null) {
108 return new MutableThreadContextStack();
109 }
110 return values.copy();
111 }
112
113 @Override
114 public boolean equals(final Object obj) {
115 if (this == obj) {
116 return true;
117 }
118 if (obj == null) {
119 return false;
120 }
121 if (obj instanceof DefaultThreadContextStack) {
122 final DefaultThreadContextStack other = (DefaultThreadContextStack) obj;
123 if (this.useStack != other.useStack) {
124 return false;
125 }
126 }
127 if (!(obj instanceof ThreadContextStack)) {
128 return false;
129 }
130 final ThreadContextStack other = (ThreadContextStack) obj;
131 final MutableThreadContextStack values = STACK.get();
132 if (values == null) {
133 return false;
134 }
135 return values.equals(other);
136 }
137
138 @Override
139 public int getDepth() {
140 final MutableThreadContextStack values = STACK.get();
141 return values == null ? 0 : values.getDepth();
142 }
143
144 @Override
145 public int hashCode() {
146 final MutableThreadContextStack values = STACK.get();
147 final int prime = 31;
148 int result = 1;
149
150 result = prime * result + ((values == null) ? 0 : values.hashCode());
151 return result;
152 }
153
154 @Override
155 public boolean isEmpty() {
156 final MutableThreadContextStack values = STACK.get();
157 return values == null || values.isEmpty();
158 }
159
160 @Override
161 public Iterator<String> iterator() {
162 final MutableThreadContextStack values = STACK.get();
163 if (values == null) {
164 final List<String> empty = Collections.emptyList();
165 return empty.iterator();
166 }
167 return values.iterator();
168 }
169
170 @Override
171 public String peek() {
172 final MutableThreadContextStack values = STACK.get();
173 if (values == null || values.size() == 0) {
174 return Strings.EMPTY;
175 }
176 return values.peek();
177 }
178
179 @Override
180 public String pop() {
181 if (!useStack) {
182 return Strings.EMPTY;
183 }
184 final MutableThreadContextStack values = STACK.get();
185 if (values == null || values.size() == 0) {
186
187 return Strings.EMPTY;
188 }
189 final MutableThreadContextStack copy = (MutableThreadContextStack) values.copy();
190 final String result = copy.pop();
191 copy.freeze();
192 STACK.set(copy);
193 return result;
194 }
195
196 @Override
197 public void push(final String message) {
198 if (!useStack) {
199 return;
200 }
201 add(message);
202 }
203
204 @Override
205 public boolean remove(final Object o) {
206 if (!useStack) {
207 return false;
208 }
209 final MutableThreadContextStack values = STACK.get();
210 if (values == null || values.size() == 0) {
211 return false;
212 }
213 final MutableThreadContextStack copy = (MutableThreadContextStack) values.copy();
214 final boolean result = copy.remove(o);
215 copy.freeze();
216 STACK.set(copy);
217 return result;
218 }
219
220 @Override
221 public boolean removeAll(final Collection<?> objects) {
222 if (!useStack || objects.isEmpty()) {
223 return false;
224 }
225 final MutableThreadContextStack values = STACK.get();
226 if (values == null || values.isEmpty()) {
227 return false;
228 }
229 final MutableThreadContextStack copy = (MutableThreadContextStack) values.copy();
230 final boolean result = copy.removeAll(objects);
231 copy.freeze();
232 STACK.set(copy);
233 return result;
234 }
235
236 @Override
237 public boolean retainAll(final Collection<?> objects) {
238 if (!useStack || objects.isEmpty()) {
239 return false;
240 }
241 final MutableThreadContextStack values = STACK.get();
242 if (values == null || values.isEmpty()) {
243 return false;
244 }
245 final MutableThreadContextStack copy = (MutableThreadContextStack) values.copy();
246 final boolean result = copy.retainAll(objects);
247 copy.freeze();
248 STACK.set(copy);
249 return result;
250 }
251
252 @Override
253 public int size() {
254 final MutableThreadContextStack values = STACK.get();
255 return values == null ? 0 : values.size();
256 }
257
258 @Override
259 public Object[] toArray() {
260 final MutableThreadContextStack result = STACK.get();
261 if (result == null) {
262 return new String[0];
263 }
264 return result.toArray(new Object[result.size()]);
265 }
266
267 @Override
268 public <T> T[] toArray(final T[] ts) {
269 final MutableThreadContextStack result = STACK.get();
270 if (result == null) {
271 if (ts.length > 0) {
272 ts[0] = null;
273 }
274 return ts;
275 }
276 return result.toArray(ts);
277 }
278
279 @Override
280 public String toString() {
281 final MutableThreadContextStack values = STACK.get();
282 return values == null ? "[]" : values.toString();
283 }
284
285 @Override
286 public void formatTo(final StringBuilder buffer) {
287 final MutableThreadContextStack values = STACK.get();
288 if (values == null) {
289 buffer.append("[]");
290 } else {
291 StringBuilders.appendValue(buffer, values);
292 }
293 }
294
295 @Override
296 public void trim(final int depth) {
297 if (depth < 0) {
298 throw new IllegalArgumentException("Maximum stack depth cannot be negative");
299 }
300 final MutableThreadContextStack values = STACK.get();
301 if (values == null) {
302 return;
303 }
304 final MutableThreadContextStack copy = (MutableThreadContextStack) values.copy();
305 copy.trim(depth);
306 copy.freeze();
307 STACK.set(copy);
308 }
309
310
311
312
313
314
315 @Override
316 public ContextStack getImmutableStackOrNull() {
317 return STACK.get();
318 }
319 }