    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    }