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