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