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