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.Iterator;
022import java.util.List;
023import java.util.concurrent.TimeUnit;
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.LifeCycle2;
030import org.apache.logging.log4j.core.LogEvent;
031import org.apache.logging.log4j.core.Logger;
032import org.apache.logging.log4j.core.config.Node;
033import org.apache.logging.log4j.core.config.plugins.Plugin;
034import org.apache.logging.log4j.core.config.plugins.PluginElement;
035import org.apache.logging.log4j.core.config.plugins.PluginFactory;
036import org.apache.logging.log4j.core.util.ObjectArrayIterator;
037import org.apache.logging.log4j.message.Message;
038import org.apache.logging.log4j.util.PerformanceSensitive;
039
040/**
041 * Composes and invokes one or more filters.
042 */
043@Plugin(name = "filters", category = Node.CATEGORY, printObject = true)
044@PerformanceSensitive("allocation")
045public final class CompositeFilter extends AbstractLifeCycle implements Iterable<Filter>, Filter {
046
047    private static final Filter[] EMPTY_FILTERS = new Filter[0];
048    private final Filter[] filters;
049
050    private CompositeFilter() {
051        this.filters = EMPTY_FILTERS;
052    }
053
054    private CompositeFilter(final Filter[] filters) {
055        this.filters = filters == null ? EMPTY_FILTERS : filters;
056    }
057
058    public CompositeFilter addFilter(final Filter filter) {
059        if (filter == null) {
060            // null does nothing
061            return this;
062        }
063        if (filter instanceof CompositeFilter) {
064            final int size = this.filters.length + ((CompositeFilter) filter).size();
065            final Filter[] copy = Arrays.copyOf(this.filters, size);
066            final int index = this.filters.length;
067            for (final Filter currentFilter : ((CompositeFilter) filter).filters) {
068                copy[index] = currentFilter;
069            }
070            return new CompositeFilter(copy);
071        }
072        final Filter[] copy = Arrays.copyOf(this.filters, this.filters.length + 1);
073        copy[this.filters.length] = filter;
074        return new CompositeFilter(copy);
075    }
076
077    public CompositeFilter removeFilter(final Filter filter) {
078        if (filter == null) {
079            // null does nothing
080            return this;
081        }
082        // This is not a great implementation but simpler than copying Apache Commons
083        // Lang ArrayUtils.removeElement() and associated bits (MutableInt),
084        // which is OK since removing a filter should not be on the critical path.
085        final List<Filter> filterList = new ArrayList<>(Arrays.asList(this.filters));
086        if (filter instanceof CompositeFilter) {
087            for (final Filter currentFilter : ((CompositeFilter) filter).filters) {
088                filterList.remove(currentFilter);
089            }
090        } else {
091            filterList.remove(filter);
092        }
093        return new CompositeFilter(filterList.toArray(new Filter[this.filters.length - 1]));
094    }
095
096    @Override
097    public Iterator<Filter> iterator() {
098        return new ObjectArrayIterator<>(filters);
099    }
100
101    /**
102     * Gets a new list over the internal filter array.
103     *
104     * @return a new list over the internal filter array
105     * @deprecated Use {@link #getFiltersArray()}
106     */
107    @Deprecated
108    public List<Filter> getFilters() {
109        return Arrays.asList(filters);
110    }
111
112    public Filter[] getFiltersArray() {
113        return filters;
114    }
115
116    /**
117     * Returns whether this composite contains any filters.
118     *
119     * @return whether this composite contains any filters.
120     */
121    public boolean isEmpty() {
122        return this.filters.length == 0;
123    }
124
125    public int size() {
126        return filters.length;
127    }
128
129    @Override
130    public void start() {
131        this.setStarting();
132        for (final Filter filter : filters) {
133            filter.start();
134        }
135        this.setStarted();
136    }
137
138    @Override
139    public boolean stop(final long timeout, final TimeUnit timeUnit) {
140        this.setStopping();
141        for (final Filter filter : filters) {
142            if (filter instanceof LifeCycle2) {
143                ((LifeCycle2) filter).stop(timeout, timeUnit);
144            } else {
145                filter.stop();
146            }
147        }
148        setStopped();
149        return true;
150    }
151
152    /**
153     * Returns the result that should be returned when the filter does not match the event.
154     *
155     * @return the Result that should be returned when the filter does not match the event.
156     */
157    @Override
158    public Result getOnMismatch() {
159        return Result.NEUTRAL;
160    }
161
162    /**
163     * Returns the result that should be returned when the filter matches the event.
164     *
165     * @return the Result that should be returned when the filter matches the event.
166     */
167    @Override
168    public Result getOnMatch() {
169        return Result.NEUTRAL;
170    }
171
172    /**
173     * Filter an event.
174     *
175     * @param logger
176     *            The Logger.
177     * @param level
178     *            The event logging Level.
179     * @param marker
180     *            The Marker for the event or null.
181     * @param msg
182     *            String text to filter on.
183     * @param params
184     *            An array of parameters or null.
185     * @return the Result.
186     */
187    @Override
188    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
189            final Object... params) {
190        Result result = Result.NEUTRAL;
191        for (int i = 0; i < filters.length; i++) {
192            result = filters[i].filter(logger, level, marker, msg, params);
193            if (result == Result.ACCEPT || result == Result.DENY) {
194                return result;
195            }
196        }
197        return result;
198    }
199
200    /**
201     * Filter an event.
202     *
203     * @param logger
204     *            The Logger.
205     * @param level
206     *            The event logging Level.
207     * @param marker
208     *            The Marker for the event or null.
209     * @param msg
210     *            String text to filter on.
211     * @param p0 the message parameters
212     * @return the Result.
213     */
214    @Override
215    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
216            final Object p0) {
217        Result result = Result.NEUTRAL;
218        for (int i = 0; i < filters.length; i++) {
219            result = filters[i].filter(logger, level, marker, msg, p0);
220            if (result == Result.ACCEPT || result == Result.DENY) {
221                return result;
222            }
223        }
224        return result;
225    }
226
227    /**
228     * Filter an event.
229     *
230     * @param logger
231     *            The Logger.
232     * @param level
233     *            The event logging Level.
234     * @param marker
235     *            The Marker for the event or null.
236     * @param msg
237     *            String text to filter on.
238     * @param p0 the message parameters
239     * @param p1 the message parameters
240     * @return the Result.
241     */
242    @Override
243    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
244            final Object p0, final Object p1) {
245        Result result = Result.NEUTRAL;
246        for (int i = 0; i < filters.length; i++) {
247            result = filters[i].filter(logger, level, marker, msg, p0, p1);
248            if (result == Result.ACCEPT || result == Result.DENY) {
249                return result;
250            }
251        }
252        return result;
253    }
254
255    /**
256     * Filter an event.
257     *
258     * @param logger
259     *            The Logger.
260     * @param level
261     *            The event logging Level.
262     * @param marker
263     *            The Marker for the event or null.
264     * @param msg
265     *            String text to filter on.
266     * @param p0 the message parameters
267     * @param p1 the message parameters
268     * @param p2 the message parameters
269     * @return the Result.
270     */
271    @Override
272    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
273            final Object p0, final Object p1, final Object p2) {
274        Result result = Result.NEUTRAL;
275        for (int i = 0; i < filters.length; i++) {
276            result = filters[i].filter(logger, level, marker, msg, p0, p1, p2);
277            if (result == Result.ACCEPT || result == Result.DENY) {
278                return result;
279            }
280        }
281        return result;
282    }
283
284    /**
285     * Filter an event.
286     *
287     * @param logger
288     *            The Logger.
289     * @param level
290     *            The event logging Level.
291     * @param marker
292     *            The Marker for the event or null.
293     * @param msg
294     *            String text to filter on.
295     * @param p0 the message parameters
296     * @param p1 the message parameters
297     * @param p2 the message parameters
298     * @param p3 the message parameters
299     * @return the Result.
300     */
301    @Override
302    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
303            final Object p0, final Object p1, final Object p2, final Object p3) {
304        Result result = Result.NEUTRAL;
305        for (int i = 0; i < filters.length; i++) {
306            result = filters[i].filter(logger, level, marker, msg, p0, p1, p2, p3);
307            if (result == Result.ACCEPT || result == Result.DENY) {
308                return result;
309            }
310        }
311        return result;
312    }
313
314    /**
315     * Filter an event.
316     *
317     * @param logger
318     *            The Logger.
319     * @param level
320     *            The event logging Level.
321     * @param marker
322     *            The Marker for the event or null.
323     * @param msg
324     *            String text to filter on.
325     * @param p0 the message parameters
326     * @param p1 the message parameters
327     * @param p2 the message parameters
328     * @param p3 the message parameters
329     * @param p4 the message parameters
330     * @return the Result.
331     */
332    @Override
333    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
334            final Object p0, final Object p1, final Object p2, final Object p3,
335            final Object p4) {
336        Result result = Result.NEUTRAL;
337        for (int i = 0; i < filters.length; i++) {
338            result = filters[i].filter(logger, level, marker, msg, p0, p1, p2, p3, p4);
339            if (result == Result.ACCEPT || result == Result.DENY) {
340                return result;
341            }
342        }
343        return result;
344    }
345
346    /**
347     * Filter an event.
348     *
349     * @param logger
350     *            The Logger.
351     * @param level
352     *            The event logging Level.
353     * @param marker
354     *            The Marker for the event or null.
355     * @param msg
356     *            String text to filter on.
357     * @param p0 the message parameters
358     * @param p1 the message parameters
359     * @param p2 the message parameters
360     * @param p3 the message parameters
361     * @param p4 the message parameters
362     * @param p5 the message parameters
363     * @return the Result.
364     */
365    @Override
366    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
367            final Object p0, final Object p1, final Object p2, final Object p3,
368            final Object p4, final Object p5) {
369        Result result = Result.NEUTRAL;
370        for (int i = 0; i < filters.length; i++) {
371            result = filters[i].filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5);
372            if (result == Result.ACCEPT || result == Result.DENY) {
373                return result;
374            }
375        }
376        return result;
377    }
378
379    /**
380     * Filter an event.
381     *
382     * @param logger
383     *            The Logger.
384     * @param level
385     *            The event logging Level.
386     * @param marker
387     *            The Marker for the event or null.
388     * @param msg
389     *            String text to filter on.
390     * @param p0 the message parameters
391     * @param p1 the message parameters
392     * @param p2 the message parameters
393     * @param p3 the message parameters
394     * @param p4 the message parameters
395     * @param p5 the message parameters
396     * @param p6 the message parameters
397     * @return the Result.
398     */
399    @Override
400    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
401            final Object p0, final Object p1, final Object p2, final Object p3,
402            final Object p4, final Object p5, final Object p6) {
403        Result result = Result.NEUTRAL;
404        for (int i = 0; i < filters.length; i++) {
405            result = filters[i].filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5, p6);
406            if (result == Result.ACCEPT || result == Result.DENY) {
407                return result;
408            }
409        }
410        return result;
411    }
412
413    /**
414     * Filter an event.
415     *
416     * @param logger
417     *            The Logger.
418     * @param level
419     *            The event logging Level.
420     * @param marker
421     *            The Marker for the event or null.
422     * @param msg
423     *            String text to filter on.
424     * @param p0 the message parameters
425     * @param p1 the message parameters
426     * @param p2 the message parameters
427     * @param p3 the message parameters
428     * @param p4 the message parameters
429     * @param p5 the message parameters
430     * @param p6 the message parameters
431     * @param p7 the message parameters
432     * @return the Result.
433     */
434    @Override
435    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
436            final Object p0, final Object p1, final Object p2, final Object p3,
437            final Object p4, final Object p5, final Object p6,
438            final Object p7) {
439        Result result = Result.NEUTRAL;
440        for (int i = 0; i < filters.length; i++) {
441            result = filters[i].filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5, p6, p7);
442            if (result == Result.ACCEPT || result == Result.DENY) {
443                return result;
444            }
445        }
446        return result;
447    }
448
449    /**
450     * Filter an event.
451     *
452     * @param logger
453     *            The Logger.
454     * @param level
455     *            The event logging Level.
456     * @param marker
457     *            The Marker for the event or null.
458     * @param msg
459     *            String text to filter on.
460     * @param p0 the message parameters
461     * @param p1 the message parameters
462     * @param p2 the message parameters
463     * @param p3 the message parameters
464     * @param p4 the message parameters
465     * @param p5 the message parameters
466     * @param p6 the message parameters
467     * @param p7 the message parameters
468     * @param p8 the message parameters
469     * @return the Result.
470     */
471    @Override
472    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
473            final Object p0, final Object p1, final Object p2, final Object p3,
474            final Object p4, final Object p5, final Object p6,
475            final Object p7, final Object p8) {
476        Result result = Result.NEUTRAL;
477        for (int i = 0; i < filters.length; i++) {
478            result = filters[i].filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5, p6, p7, p8);
479            if (result == Result.ACCEPT || result == Result.DENY) {
480                return result;
481            }
482        }
483        return result;
484    }
485
486    /**
487     * Filter an event.
488     *
489     * @param logger
490     *            The Logger.
491     * @param level
492     *            The event logging Level.
493     * @param marker
494     *            The Marker for the event or null.
495     * @param msg
496     *            String text to filter on.
497     * @param p0 the message parameters
498     * @param p1 the message parameters
499     * @param p2 the message parameters
500     * @param p3 the message parameters
501     * @param p4 the message parameters
502     * @param p5 the message parameters
503     * @param p6 the message parameters
504     * @param p7 the message parameters
505     * @param p8 the message parameters
506     * @param p9 the message parameters
507     * @return the Result.
508     */
509    @Override
510    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
511            final Object p0, final Object p1, final Object p2, final Object p3,
512            final Object p4, final Object p5, final Object p6,
513            final Object p7, final Object p8, final Object p9) {
514        Result result = Result.NEUTRAL;
515        for (int i = 0; i < filters.length; i++) {
516            result = filters[i].filter(logger, level, marker, msg, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
517            if (result == Result.ACCEPT || result == Result.DENY) {
518                return result;
519            }
520        }
521        return result;
522    }
523
524    /**
525     * Filter an event.
526     *
527     * @param logger
528     *            The Logger.
529     * @param level
530     *            The event logging Level.
531     * @param marker
532     *            The Marker for the event or null.
533     * @param msg
534     *            Any Object.
535     * @param t
536     *            A Throwable or null.
537     * @return the Result.
538     */
539    @Override
540    public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
541            final Throwable t) {
542        Result result = Result.NEUTRAL;
543        for (int i = 0; i < filters.length; i++) {
544            result = filters[i].filter(logger, level, marker, msg, t);
545            if (result == Result.ACCEPT || result == Result.DENY) {
546                return result;
547            }
548        }
549        return result;
550    }
551
552    /**
553     * Filter an event.
554     *
555     * @param logger
556     *            The Logger.
557     * @param level
558     *            The event logging Level.
559     * @param marker
560     *            The Marker for the event or null.
561     * @param msg
562     *            The Message
563     * @param t
564     *            A Throwable or null.
565     * @return the Result.
566     */
567    @Override
568    public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
569            final Throwable t) {
570        Result result = Result.NEUTRAL;
571        for (int i = 0; i < filters.length; i++) {
572            result = filters[i].filter(logger, level, marker, msg, t);
573            if (result == Result.ACCEPT || result == Result.DENY) {
574                return result;
575            }
576        }
577        return result;
578    }
579
580    /**
581     * Filter an event.
582     *
583     * @param event
584     *            The Event to filter on.
585     * @return the Result.
586     */
587    @Override
588    public Result filter(final LogEvent event) {
589        Result result = Result.NEUTRAL;
590        for (int i = 0; i < filters.length; i++) {
591            result = filters[i].filter(event);
592            if (result == Result.ACCEPT || result == Result.DENY) {
593                return result;
594            }
595        }
596        return result;
597    }
598
599    @Override
600    public String toString() {
601        final StringBuilder sb = new StringBuilder();
602        for (int i = 0; i < filters.length; i++) {
603            if (sb.length() == 0) {
604                sb.append('{');
605            } else {
606                sb.append(", ");
607            }
608            sb.append(filters[i].toString());
609        }
610        if (sb.length() > 0) {
611            sb.append('}');
612        }
613        return sb.toString();
614    }
615
616    /**
617     * Creates a CompositeFilter.
618     *
619     * @param filters
620     *            An array of Filters to call.
621     * @return The CompositeFilter.
622     */
623    @PluginFactory
624    public static CompositeFilter createFilters(@PluginElement("Filters") final Filter[] filters) {
625        return new CompositeFilter(filters);
626    }
627
628}