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 import java.util.NoSuchElementException;
24
25 import org.apache.logging.log4j.ThreadContext.ContextStack;
26 import org.apache.logging.log4j.util.Strings;
27
28
29
30
31
32 public class DefaultThreadContextStack implements ThreadContextStack {
33
34 private static final long serialVersionUID = 5050501L;
35
36 private static final ThreadLocal<MutableThreadContextStack> stack = new ThreadLocal<MutableThreadContextStack>();
37
38 private final boolean useStack;
39
40 public DefaultThreadContextStack(final boolean useStack) {
41 this.useStack = useStack;
42 }
43
44 private MutableThreadContextStack getNonNullStackCopy() {
45 final MutableThreadContextStack values = stack.get();
46 return (MutableThreadContextStack) (values == null ? new MutableThreadContextStack() : values.copy());
47 }
48
49 @Override
50 public boolean add(final String s) {
51 if (!useStack) {
52 return false;
53 }
54 final MutableThreadContextStack copy = getNonNullStackCopy();
55 copy.add(s);
56 copy.freeze();
57 stack.set(copy);
58 return true;
59 }
60
61 @Override
62 public boolean addAll(final Collection<? extends String> strings) {
63 if (!useStack || strings.isEmpty()) {
64 return false;
65 }
66 final MutableThreadContextStack copy = getNonNullStackCopy();
67 copy.addAll(strings);
68 copy.freeze();
69 stack.set(copy);
70 return true;
71 }
72
73 @Override
74 public List<String> asList() {
75 final MutableThreadContextStack values = stack.get();
76 if (values == null) {
77 return Collections.emptyList();
78 }
79 return values.asList();
80 }
81
82 @Override
83 public void clear() {
84 stack.remove();
85 }
86
87 @Override
88 public boolean contains(final Object o) {
89 final MutableThreadContextStack values = stack.get();
90 return values != null && values.contains(o);
91 }
92
93 @Override
94 public boolean containsAll(final Collection<?> objects) {
95 if (objects.isEmpty()) {
96 return true;
97
98 }
99 final MutableThreadContextStack values = stack.get();
100 return values != null && values.containsAll(objects);
101 }
102
103 @Override
104 public ThreadContextStack copy() {
105 MutableThreadContextStack values = null;
106 if (!useStack || (values = stack.get()) == null) {
107 return new MutableThreadContextStack();
108 }
109 return values.copy();
110 }
111
112 @Override
113 public boolean equals(final Object obj) {
114 if (this == obj) {
115 return true;
116 }
117 if (obj == null) {
118 return false;
119 }
120 if (obj instanceof DefaultThreadContextStack) {
121 final DefaultThreadContextStack other = (DefaultThreadContextStack) obj;
122 if (this.useStack != other.useStack) {
123 return false;
124 }
125 }
126 if (!(obj instanceof ThreadContextStack)) {
127 return false;
128 }
129 final ThreadContextStack other = (ThreadContextStack) obj;
130 final MutableThreadContextStack values = stack.get();
131 if (values == null) {
132 return other == null;
133 }
134 return values.equals(other);
135 }
136
137 @Override
138 public int getDepth() {
139 final MutableThreadContextStack values = stack.get();
140 return values == null ? 0 : values.getDepth();
141 }
142
143 @Override
144 public int hashCode() {
145 final MutableThreadContextStack values = stack.get();
146 final int prime = 31;
147 int result = 1;
148
149 result = prime * result + ((values == null) ? 0 : values.hashCode());
150 return result;
151 }
152
153 @Override
154 public boolean isEmpty() {
155 final MutableThreadContextStack values = stack.get();
156 return values == null || values.isEmpty();
157 }
158
159 @Override
160 public Iterator<String> iterator() {
161 final MutableThreadContextStack values = stack.get();
162 if (values == null) {
163 final List<String> empty = Collections.emptyList();
164 return empty.iterator();
165 }
166 return values.iterator();
167 }
168
169 @Override
170 public String peek() {
171 final MutableThreadContextStack values = stack.get();
172 if (values == null || values.size() == 0) {
173 return null;
174 }
175 return values.peek();
176 }
177
178 @Override
179 public String pop() {
180 if (!useStack) {
181 return Strings.EMPTY;
182 }
183 final MutableThreadContextStack values = stack.get();
184 if (values == null || values.size() == 0) {
185 throw new NoSuchElementException("The ThreadContext stack is 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 }