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 */ 017package org.apache.logging.log4j.spi; 018 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.Iterator; 022import java.util.List; 023 024import org.apache.logging.log4j.ThreadContext.ContextStack; 025 026/** 027 * 028 */ 029public 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}