View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
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  
24  import org.apache.logging.log4j.ThreadContext.ContextStack;
25  import org.apache.logging.log4j.util.StringBuilderFormattable;
26  
27  /**
28   * TODO
29   */
30  public class MutableThreadContextStack implements ThreadContextStack, StringBuilderFormattable {
31  
32      private static final long serialVersionUID = 50505011L;
33  
34      /**
35       * The underlying list (never null).
36       */
37      private final List<String> list;
38      private boolean frozen;
39  
40      /**
41       * Constructs an empty MutableThreadContextStack.
42       */
43      public MutableThreadContextStack() {
44          this(new ArrayList<String>());
45      }
46  
47      /**
48       * Constructs a new instance.
49       * @param list
50       */
51      public MutableThreadContextStack(final List<String> list) {
52          this.list = new ArrayList<>(list);
53      }
54  
55      private MutableThreadContextStack(final MutableThreadContextStack stack) {
56          this.list = new ArrayList<>(stack.list);
57      }
58  
59      private void checkInvariants() {
60          if (frozen) {
61              throw new UnsupportedOperationException("context stack has been frozen");
62          }
63      }
64  
65      @Override
66      public String pop() {
67          checkInvariants();
68          if (list.isEmpty()) {
69              return null;
70          }
71          final int last = list.size() - 1;
72          final String result = list.remove(last);
73          return result;
74      }
75  
76      @Override
77      public String peek() {
78          if (list.isEmpty()) {
79              return null;
80          }
81          final int last = list.size() - 1;
82          return list.get(last);
83      }
84  
85      @Override
86      public void push(final String message) {
87          checkInvariants();
88          list.add(message);
89      }
90  
91      @Override
92      public int getDepth() {
93          return list.size();
94      }
95  
96      @Override
97      public List<String> asList() {
98          return list;
99      }
100 
101     @Override
102     public void trim(final int depth) {
103         checkInvariants();
104         if (depth < 0) {
105             throw new IllegalArgumentException("Maximum stack depth cannot be negative");
106         }
107         if (list == null) {
108             return;
109         }
110         final List<String> copy = new ArrayList<>(list.size());
111         final int count = Math.min(depth, list.size());
112         for (int i = 0; i < count; i++) {
113             copy.add(list.get(i));
114         }
115         list.clear();
116         list.addAll(copy);
117     }
118 
119     @Override
120     public ThreadContextStack copy() {
121         return new MutableThreadContextStack(this);
122     }
123 
124     @Override
125     public void clear() {
126         checkInvariants();
127         list.clear();
128     }
129 
130     @Override
131     public int size() {
132         return list.size();
133     }
134 
135     @Override
136     public boolean isEmpty() {
137         return list.isEmpty();
138     }
139 
140     @Override
141     public boolean contains(final Object o) {
142         return list.contains(o);
143     }
144 
145     @Override
146     public Iterator<String> iterator() {
147         return list.iterator();
148     }
149 
150     @Override
151     public Object[] toArray() {
152         return list.toArray();
153     }
154 
155     @Override
156     public <T> T[] toArray(final T[] ts) {
157         return list.toArray(ts);
158     }
159 
160     @Override
161     public boolean add(final String s) {
162         checkInvariants();
163         return list.add(s);
164     }
165 
166     @Override
167     public boolean remove(final Object o) {
168         checkInvariants();
169         return list.remove(o);
170     }
171 
172     @Override
173     public boolean containsAll(final Collection<?> objects) {
174         return list.containsAll(objects);
175     }
176 
177     @Override
178     public boolean addAll(final Collection<? extends String> strings) {
179         checkInvariants();
180         return list.addAll(strings);
181     }
182 
183     @Override
184     public boolean removeAll(final Collection<?> objects) {
185         checkInvariants();
186         return list.removeAll(objects);
187     }
188 
189     @Override
190     public boolean retainAll(final Collection<?> objects) {
191         checkInvariants();
192         return list.retainAll(objects);
193     }
194 
195     @Override
196     public String toString() {
197         return String.valueOf(list);
198     }
199 
200     @Override
201     public void formatTo(final StringBuilder buffer) {
202         buffer.append('[');
203         for (int i = 0; i < list.size(); i++) {
204             if (i > 0) {
205                 buffer.append(',').append(' ');
206             }
207             buffer.append(list.get(i));
208         }
209         buffer.append(']');
210     }
211 
212     @Override
213     public int hashCode() {
214         final int prime = 31;
215         int result = 1;
216         result = prime * result + ((this.list == null) ? 0 : this.list.hashCode());
217         return result;
218     }
219 
220     @Override
221     public boolean equals(final Object obj) {
222         if (this == obj) {
223             return true;
224         }
225         if (obj == null) {
226             return false;
227         }
228         if (!(obj instanceof ThreadContextStack)) {
229             return false;
230         }
231         final ThreadContextStack other = (ThreadContextStack) obj;
232         final List<String> otherAsList = other.asList();
233         if (this.list == null) {
234             if (otherAsList != null) {
235                 return false;
236             }
237         } else if (!this.list.equals(otherAsList)) {
238             return false;
239         }
240         return true;
241     }
242 
243     @Override
244     public ContextStack getImmutableStackOrNull() {
245         return copy();
246     }
247 
248     /**
249      * "Freezes" this context stack so it becomes immutable: all mutator methods will throw an exception from now on.
250      */
251     public void freeze() {
252         frozen = true;
253     }
254 
255     /**
256      * Returns whether this context stack is frozen.
257      * @return whether this context stack is frozen.
258      */
259     public boolean isFrozen() {
260         return frozen;
261     }
262 }