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