001/*
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2026, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v2.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.classic.spi;
015
016import java.util.concurrent.CopyOnWriteArrayList;
017
018import org.slf4j.Marker;
019
020import ch.qos.logback.classic.Level;
021import ch.qos.logback.classic.Logger;
022import ch.qos.logback.classic.turbo.TurboFilter;
023import ch.qos.logback.core.spi.FilterReply;
024
025/**
026 * Implementation of TurboFilterAttachable.
027 *
028 * @author Ceki Gülcü
029 */
030final public class TurboFilterList extends CopyOnWriteArrayList<TurboFilter> {
031
032    private static final long serialVersionUID = 1L;
033
034    /**
035     * Loop through the filters in the chain. As soon as a filter decides on ACCEPT
036     * or DENY, then that value is returned. If all turbo filters return NEUTRAL,
037     * then NEUTRAL is returned.
038     */
039    public FilterReply getTurboFilterChainDecision(final Marker marker, final Logger logger, final Level level,
040                                                   final String format, final Object[] params, final Throwable t) {
041
042        final int size = size();
043        // caller may have already performed this check, but we do it here as well to be sure
044        if (size == 0) {
045            return FilterReply.NEUTRAL;
046        }
047
048        if (size == 1) {
049            try {
050                TurboFilter tf = get(0);
051                return tf.decide(marker, logger, level, format, params, t);
052            } catch (IndexOutOfBoundsException iobe) {
053                // concurrent modification detected, fall through to the general case
054                return FilterReply.NEUTRAL;
055            }
056        }
057
058
059        for (TurboFilter tf : this) {
060            final FilterReply r = tf.decide(marker, logger, level, format, params, t);
061            if (r == FilterReply.DENY || r == FilterReply.ACCEPT) {
062                return r;
063            }
064        }
065
066        return FilterReply.NEUTRAL;
067    }
068
069
070    /**
071     * Loop through the filters in the chain. As soon as a filter decides on ACCEPT
072     * or DENY, then that value is returned. If all turbo filters return NEUTRAL,
073     * then NEUTRAL is returned.
074     *
075     * @param logger  the logger requesting a decision
076     * @param slf4jEvent the SLF4J logging event
077     * @return the decision of the turbo filter chain
078     * @since 1.5.21
079     */
080    public FilterReply getTurboFilterChainDecision(Logger logger, org.slf4j.event.LoggingEvent slf4jEvent) {
081
082        final int size = size();
083        // caller may have already performed this check, but we do it here as well to be sure
084        if (size == 0) {
085            return FilterReply.NEUTRAL;
086        }
087
088        if (size == 1) {
089            try {
090                TurboFilter tf = get(0);
091                return tf.decide(logger, slf4jEvent);
092            } catch (IndexOutOfBoundsException iobe) {
093                // concurrent modification detected, fall through to the general case
094                return FilterReply.NEUTRAL;
095            }
096        }
097
098
099        for (TurboFilter tf : this) {
100            final FilterReply r = tf.decide(logger, slf4jEvent);
101            if (r == FilterReply.DENY || r == FilterReply.ACCEPT) {
102                return r;
103            }
104        }
105
106        return FilterReply.NEUTRAL;
107    }
108
109}