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