1   /*
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2026, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v2.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.classic.spi;
15  
16  import java.util.concurrent.CopyOnWriteArrayList;
17  
18  import org.slf4j.Marker;
19  
20  import ch.qos.logback.classic.Level;
21  import ch.qos.logback.classic.Logger;
22  import ch.qos.logback.classic.turbo.TurboFilter;
23  import ch.qos.logback.core.spi.FilterReply;
24  
25  /**
26   * Implementation of TurboFilterAttachable.
27   *
28   * @author Ceki Gülcü
29   */
30  final public class TurboFilterList extends CopyOnWriteArrayList<TurboFilter> {
31  
32      private static final long serialVersionUID = 1L;
33  
34      /**
35       * Loop through the filters in the chain. As soon as a filter decides on ACCEPT
36       * or DENY, then that value is returned. If all turbo filters return NEUTRAL,
37       * then NEUTRAL is returned.
38       */
39      public FilterReply getTurboFilterChainDecision(final Marker marker, final Logger logger, final Level level,
40                                                     final String format, final Object[] params, final Throwable t) {
41  
42          final int size = size();
43          // caller may have already performed this check, but we do it here as well to be sure
44          if (size == 0) {
45              return FilterReply.NEUTRAL;
46          }
47  
48          if (size == 1) {
49              try {
50                  TurboFilter tf = get(0);
51                  return tf.decide(marker, logger, level, format, params, t);
52              } catch (IndexOutOfBoundsException iobe) {
53                  // concurrent modification detected, fall through to the general case
54                  return FilterReply.NEUTRAL;
55              }
56          }
57  
58  
59          for (TurboFilter tf : this) {
60              final FilterReply r = tf.decide(marker, logger, level, format, params, t);
61              if (r == FilterReply.DENY || r == FilterReply.ACCEPT) {
62                  return r;
63              }
64          }
65  
66          return FilterReply.NEUTRAL;
67      }
68  
69  
70      /**
71       * Loop through the filters in the chain. As soon as a filter decides on ACCEPT
72       * or DENY, then that value is returned. If all turbo filters return NEUTRAL,
73       * then NEUTRAL is returned.
74       *
75       * @param logger  the logger requesting a decision
76       * @param slf4jEvent the SLF4J logging event
77       * @return the decision of the turbo filter chain
78       * @since 1.5.21
79       */
80      public FilterReply getTurboFilterChainDecision(Logger logger, org.slf4j.event.LoggingEvent slf4jEvent) {
81  
82          final int size = size();
83          // caller may have already performed this check, but we do it here as well to be sure
84          if (size == 0) {
85              return FilterReply.NEUTRAL;
86          }
87  
88          if (size == 1) {
89              try {
90                  TurboFilter tf = get(0);
91                  return tf.decide(logger, slf4jEvent);
92              } catch (IndexOutOfBoundsException iobe) {
93                  // concurrent modification detected, fall through to the general case
94                  return FilterReply.NEUTRAL;
95              }
96          }
97  
98  
99          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 }