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