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