001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017 package org.apache.logging.log4j.spi;
018
019 import java.util.ArrayList;
020 import java.util.Collection;
021 import java.util.Iterator;
022 import java.util.List;
023
024 import org.apache.logging.log4j.ThreadContext.ContextStack;
025
026 /**
027 *
028 */
029 public class MutableThreadContextStack implements ThreadContextStack {
030
031 private static final long serialVersionUID = 50505011L;
032
033 /**
034 * The underlying list (never null).
035 */
036 private final List<String> list;
037 private boolean frozen;
038
039 /**
040 * Constructs an empty MutableThreadContextStack.
041 */
042 public MutableThreadContextStack() {
043 this(new ArrayList<String>());
044 }
045
046 public MutableThreadContextStack(final List<String> list) {
047 this.list = new ArrayList<String>(list);
048 }
049
050 private MutableThreadContextStack(final MutableThreadContextStack stack) {
051 this.list = new ArrayList<String>(stack.list);
052 }
053
054 private void checkInvariants() {
055 if (frozen) {
056 throw new UnsupportedOperationException("context stack has been frozen");
057 }
058 }
059
060 @Override
061 public String pop() {
062 checkInvariants();
063 if (list.isEmpty()) {
064 return null;
065 }
066 final int last = list.size() - 1;
067 final String result = list.remove(last);
068 return result;
069 }
070
071 @Override
072 public String peek() {
073 if (list.isEmpty()) {
074 return null;
075 }
076 final int last = list.size() - 1;
077 return list.get(last);
078 }
079
080 @Override
081 public void push(final String message) {
082 checkInvariants();
083 list.add(message);
084 }
085
086 @Override
087 public int getDepth() {
088 return list.size();
089 }
090
091 @Override
092 public List<String> asList() {
093 return list;
094 }
095
096 @Override
097 public void trim(final int depth) {
098 checkInvariants();
099 if (depth < 0) {
100 throw new IllegalArgumentException("Maximum stack depth cannot be negative");
101 }
102 if (list == null) {
103 return;
104 }
105 final List<String> copy = new ArrayList<String>(list.size());
106 final int count = Math.min(depth, list.size());
107 for (int i = 0; i < count; i++) {
108 copy.add(list.get(i));
109 }
110 list.clear();
111 list.addAll(copy);
112 }
113
114 @Override
115 public ThreadContextStack copy() {
116 return new MutableThreadContextStack(this);
117 }
118
119 @Override
120 public void clear() {
121 checkInvariants();
122 list.clear();
123 }
124
125 @Override
126 public int size() {
127 return list.size();
128 }
129
130 @Override
131 public boolean isEmpty() {
132 return list.isEmpty();
133 }
134
135 @Override
136 public boolean contains(final Object o) {
137 return list.contains(o);
138 }
139
140 @Override
141 public Iterator<String> iterator() {
142 return list.iterator();
143 }
144
145 @Override
146 public Object[] toArray() {
147 return list.toArray();
148 }
149
150 @Override
151 public <T> T[] toArray(final T[] ts) {
152 return list.toArray(ts);
153 }
154
155 @Override
156 public boolean add(final String s) {
157 checkInvariants();
158 return list.add(s);
159 }
160
161 @Override
162 public boolean remove(final Object o) {
163 checkInvariants();
164 return list.remove(o);
165 }
166
167 @Override
168 public boolean containsAll(final Collection<?> objects) {
169 return list.containsAll(objects);
170 }
171
172 @Override
173 public boolean addAll(final Collection<? extends String> strings) {
174 checkInvariants();
175 return list.addAll(strings);
176 }
177
178 @Override
179 public boolean removeAll(final Collection<?> objects) {
180 checkInvariants();
181 return list.removeAll(objects);
182 }
183
184 @Override
185 public boolean retainAll(final Collection<?> objects) {
186 checkInvariants();
187 return list.retainAll(objects);
188 }
189
190 @Override
191 public String toString() {
192 return String.valueOf(list);
193 }
194
195 @Override
196 public int hashCode() {
197 final int prime = 31;
198 int result = 1;
199 result = prime * result + ((this.list == null) ? 0 : this.list.hashCode());
200 return result;
201 }
202
203 @Override
204 public boolean equals(final Object obj) {
205 if (this == obj) {
206 return true;
207 }
208 if (obj == null) {
209 return false;
210 }
211 if (!(obj instanceof ThreadContextStack)) {
212 return false;
213 }
214 final ThreadContextStack other = (ThreadContextStack) obj;
215 final List<String> otherAsList = other.asList();
216 if (this.list == null) {
217 if (otherAsList != null) {
218 return false;
219 }
220 } else if (!this.list.equals(otherAsList)) {
221 return false;
222 }
223 return true;
224 }
225
226 @Override
227 public ContextStack getImmutableStackOrNull() {
228 return copy();
229 }
230
231 /**
232 * "Freezes" this context stack so it becomes immutable: all mutator methods will throw an exception from now on.
233 */
234 public void freeze() {
235 frozen = true;
236 }
237
238 public boolean isFrozen() {
239 return frozen;
240 }
241 }