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.Iterator;
22 import java.util.List;
23 import java.util.Objects;
24
25 import org.apache.logging.log4j.ThreadContext.ContextStack;
26 import org.apache.logging.log4j.util.StringBuilderFormattable;
27
28
29
30
31 public class MutableThreadContextStack implements ThreadContextStack, StringBuilderFormattable {
32
33 private static final long serialVersionUID = 50505011L;
34
35
36
37
38 private final List<String> list;
39 private boolean frozen;
40
41
42
43
44 public MutableThreadContextStack() {
45 this(new ArrayList<String>());
46 }
47
48
49
50
51
52 public MutableThreadContextStack(final List<String> list) {
53 this.list = new ArrayList<>(list);
54 }
55
56 private MutableThreadContextStack(final MutableThreadContextStack stack) {
57 this.list = new ArrayList<>(stack.list);
58 }
59
60 private void checkInvariants() {
61 if (frozen) {
62 throw new UnsupportedOperationException("context stack has been frozen");
63 }
64 }
65
66 @Override
67 public String pop() {
68 checkInvariants();
69 if (list.isEmpty()) {
70 return null;
71 }
72 final int last = list.size() - 1;
73 final String result = list.remove(last);
74 return result;
75 }
76
77 @Override
78 public String peek() {
79 if (list.isEmpty()) {
80 return null;
81 }
82 final int last = list.size() - 1;
83 return list.get(last);
84 }
85
86 @Override
87 public void push(final String message) {
88 checkInvariants();
89 list.add(message);
90 }
91
92 @Override
93 public int getDepth() {
94 return list.size();
95 }
96
97 @Override
98 public List<String> asList() {
99 return list;
100 }
101
102 @Override
103 public void trim(final int depth) {
104 checkInvariants();
105 if (depth < 0) {
106 throw new IllegalArgumentException("Maximum stack depth cannot be negative");
107 }
108 if (list == null) {
109 return;
110 }
111 final List<String> copy = new ArrayList<>(list.size());
112 final int count = Math.min(depth, list.size());
113 for (int i = 0; i < count; i++) {
114 copy.add(list.get(i));
115 }
116 list.clear();
117 list.addAll(copy);
118 }
119
120 @Override
121 public ThreadContextStack copy() {
122 return new MutableThreadContextStack(this);
123 }
124
125 @Override
126 public void clear() {
127 checkInvariants();
128 list.clear();
129 }
130
131 @Override
132 public int size() {
133 return list.size();
134 }
135
136 @Override
137 public boolean isEmpty() {
138 return list.isEmpty();
139 }
140
141 @Override
142 public boolean contains(final Object o) {
143 return list.contains(o);
144 }
145
146 @Override
147 public Iterator<String> iterator() {
148 return list.iterator();
149 }
150
151 @Override
152 public Object[] toArray() {
153 return list.toArray();
154 }
155
156 @Override
157 public <T> T[] toArray(final T[] ts) {
158 return list.toArray(ts);
159 }
160
161 @Override
162 public boolean add(final String s) {
163 checkInvariants();
164 return list.add(s);
165 }
166
167 @Override
168 public boolean remove(final Object o) {
169 checkInvariants();
170 return list.remove(o);
171 }
172
173 @Override
174 public boolean containsAll(final Collection<?> objects) {
175 return list.containsAll(objects);
176 }
177
178 @Override
179 public boolean addAll(final Collection<? extends String> strings) {
180 checkInvariants();
181 return list.addAll(strings);
182 }
183
184 @Override
185 public boolean removeAll(final Collection<?> objects) {
186 checkInvariants();
187 return list.removeAll(objects);
188 }
189
190 @Override
191 public boolean retainAll(final Collection<?> objects) {
192 checkInvariants();
193 return list.retainAll(objects);
194 }
195
196 @Override
197 public String toString() {
198 return String.valueOf(list);
199 }
200
201 @Override
202 public void formatTo(final StringBuilder buffer) {
203 buffer.append('[');
204 for (int i = 0; i < list.size(); i++) {
205 if (i > 0) {
206 buffer.append(',').append(' ');
207 }
208 buffer.append(list.get(i));
209 }
210 buffer.append(']');
211 }
212
213 @Override
214 public int hashCode() {
215 return 31 + Objects.hashCode(list);
216 }
217
218 @Override
219 public boolean equals(final Object obj) {
220 if (this == obj) {
221 return true;
222 }
223 if (obj == null) {
224 return false;
225 }
226 if (!(obj instanceof ThreadContextStack)) {
227 return false;
228 }
229 final ThreadContextStack other = (ThreadContextStack) obj;
230 final List<String> otherAsList = other.asList();
231 return Objects.equals(this.list, otherAsList);
232 }
233
234 @Override
235 public ContextStack getImmutableStackOrNull() {
236 return copy();
237 }
238
239
240
241
242 public void freeze() {
243 frozen = true;
244 }
245
246
247
248
249
250 public boolean isFrozen() {
251 return frozen;
252 }
253 }