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.core.filter;
018
019import java.util.ArrayList;
020import java.util.Arrays;
021import java.util.Collections;
022import java.util.Iterator;
023import java.util.List;
024
025import org.apache.logging.log4j.Level;
026import org.apache.logging.log4j.Marker;
027import org.apache.logging.log4j.core.AbstractLifeCycle;
028import org.apache.logging.log4j.core.Filter;
029import org.apache.logging.log4j.core.LogEvent;
030import org.apache.logging.log4j.core.Logger;
031import org.apache.logging.log4j.core.config.Node;
032import org.apache.logging.log4j.core.config.plugins.Plugin;
033import org.apache.logging.log4j.core.config.plugins.PluginElement;
034import org.apache.logging.log4j.core.config.plugins.PluginFactory;
035import org.apache.logging.log4j.message.Message;
036
037/**
038 * Composes and invokes one or more filters.
039 */
040@Plugin(name = "filters", category = Node.CATEGORY, printObject = true)
041public final class CompositeFilter extends AbstractLifeCycle implements Iterable<Filter>, Filter {
042
043    private static final long serialVersionUID = 1L;
044
045    private final List<Filter> filters;
046
047    private CompositeFilter() {
048        this.filters = new ArrayList<>();
049    }
050
051    private CompositeFilter(final List<Filter> filters) {
052        if (filters == null) {
053            this.filters = Collections.unmodifiableList(new ArrayList<Filter>());
054            return;
055        }
056        this.filters = Collections.unmodifiableList(filters);
057    }
058
059    public CompositeFilter addFilter(final Filter filter) {
060        if (filter == null) {
061            // null does nothing
062            return this;
063        }
064        final List<Filter> filterList = new ArrayList<>(this.filters);
065        filterList.add(filter);
066        return new CompositeFilter(Collections.unmodifiableList(filterList));
067    }
068
069    public CompositeFilter removeFilter(final Filter filter) {
070        if (filter == null) {
071            // null does nothing
072            return this;
073        }
074        final List<Filter> filterList = new ArrayList<>(this.filters);
075        filterList.remove(filter);
076        return new CompositeFilter(Collections.unmodifiableList(filterList));
077    }
078
079    @Override
080    public Iterator<Filter> iterator() {
081        return filters.iterator();
082    }
083
084    public List<Filter> getFilters() {
085        return filters;
086    }
087
088    /**
089     * Returns whether this composite contains any filters.
090     *
091     * @return whether this composite contains any filters.
092     */
093    public boolean isEmpty() {
094        return this.filters.isEmpty();
095    }
096
097    public int size() {
098        return filters.size();
099    }
100
101    @Override
102    public void start() {
103        this.setStarting();
104        for (final Filter filter : filters) {
105            filter.start();
106        }
107        this.setStarted();
108    }
109
110    @Override
111    public void stop() {
112        this.setStopping();
113        for (final Filter filter : filters) {
114            filter.stop();
115        }
116        this.setStopped();
117    }
118
119    /**
120     * Returns the result that should be returned when the filter does not match the event.
121     *
122     * @return the Result that should be returned when the filter does not match the event.
123     */
124    @Override
125    public Result getOnMismatch() {
126        return Result.NEUTRAL;
127    }
128
129    /**
130     * Returns the result that should be returned when the filter matches the event.
131     *
132     * @return the Result that should be returned when the filter matches the event.
133     */
134    @Override
135    public Result getOnMatch() {
136        return Result.NEUTRAL;
137    }
138
139    /**
140     * Filter an event.
141     *
142     * @param logger
143     *            The Logger.
144     * @param level
145     *            The event logging Level.
146     * @param marker
147     *            The Marker for the event or null.
148     * @param msg
149     *            String text to filter on.
150     * @param params
151     *            An array of parameters or null.
152     * @return the Result.
153     */
154    @Override
155    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
156                         final Object... params) {
157        Result result = Result.NEUTRAL;
158        for (final Filter filter : filters) {
159            result = filter.filter(logger, level, marker, msg, params);
160            if (result == Result.ACCEPT || result == Result.DENY) {
161                return result;
162            }
163        }
164        return result;
165    }
166
167    /**
168     * Filter an event.
169     *
170     * @param logger
171     *            The Logger.
172     * @param level
173     *            The event logging Level.
174     * @param marker
175     *            The Marker for the event or null.
176     * @param msg
177     *            Any Object.
178     * @param t
179     *            A Throwable or null.
180     * @return the Result.
181     */
182    @Override
183    public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
184                         final Throwable t) {
185        Result result = Result.NEUTRAL;
186        for (final Filter filter : filters) {
187            result = filter.filter(logger, level, marker, msg, t);
188            if (result == Result.ACCEPT || result == Result.DENY) {
189                return result;
190            }
191        }
192        return result;
193    }
194
195    /**
196     * Filter an event.
197     *
198     * @param logger
199     *            The Logger.
200     * @param level
201     *            The event logging Level.
202     * @param marker
203     *            The Marker for the event or null.
204     * @param msg
205     *            The Message
206     * @param t
207     *            A Throwable or null.
208     * @return the Result.
209     */
210    @Override
211    public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
212                         final Throwable t) {
213        Result result = Result.NEUTRAL;
214        for (final Filter filter : filters) {
215            result = filter.filter(logger, level, marker, msg, t);
216            if (result == Result.ACCEPT || result == Result.DENY) {
217                return result;
218            }
219        }
220        return result;
221    }
222
223    /**
224     * Filter an event.
225     *
226     * @param event
227     *            The Event to filter on.
228     * @return the Result.
229     */
230    @Override
231    public Result filter(final LogEvent event) {
232        Result result = Result.NEUTRAL;
233        for (final Filter filter : filters) {
234            result = filter.filter(event);
235            if (result == Result.ACCEPT || result == Result.DENY) {
236                return result;
237            }
238        }
239        return result;
240    }
241
242    @Override
243    public String toString() {
244        final StringBuilder sb = new StringBuilder();
245        for (final Filter filter : filters) {
246            if (sb.length() == 0) {
247                sb.append('{');
248            } else {
249                sb.append(", ");
250            }
251            sb.append(filter.toString());
252        }
253        if (sb.length() > 0) {
254            sb.append('}');
255        }
256        return sb.toString();
257    }
258
259    /**
260     * Create a CompositeFilter.
261     *
262     * @param filters
263     *            An array of Filters to call.
264     * @return The CompositeFilter.
265     */
266    @PluginFactory
267    public static CompositeFilter createFilters(@PluginElement("Filters") final Filter[] filters) {
268        final List<Filter> filterList = filters == null || filters.length == 0 ?
269            new ArrayList<Filter>() : Arrays.asList(filters);
270        return new CompositeFilter(filterList);
271    }
272
273}