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.Iterator;
020import java.util.concurrent.TimeUnit;
021
022import org.apache.logging.log4j.core.AbstractLifeCycle;
023import org.apache.logging.log4j.core.Filter;
024import org.apache.logging.log4j.core.LifeCycle2;
025import org.apache.logging.log4j.core.LogEvent;
026import org.apache.logging.log4j.core.config.plugins.PluginElement;
027
028/**
029 * Enhances a Class by allowing it to contain Filters.
030 */
031public abstract class AbstractFilterable extends AbstractLifeCycle implements Filterable {
032
033    /**
034     * Subclasses can extend this abstract Builder.
035     *
036     * @param <B> This builder class.
037     */
038    public abstract static class Builder<B extends Builder<B>> {
039
040        @PluginElement("Filter")
041        private Filter filter;
042
043        public Filter getFilter() {
044            return filter;
045        }
046
047        @SuppressWarnings("unchecked")
048        public B asBuilder() {
049            return (B) this;
050        }
051
052        public B withFilter(final Filter filter) {
053            this.filter = filter;
054            return asBuilder();
055        }
056
057    }
058
059    /**
060     * May be null.
061     */
062    private volatile Filter filter;
063
064    protected AbstractFilterable(final Filter filter) {
065        this.filter = filter;
066    }
067
068    protected AbstractFilterable() {
069    }
070
071    /**
072     * Returns the Filter.
073     * @return the Filter or null.
074     */
075    @Override
076    public Filter getFilter() {
077        return filter;
078    }
079
080    /**
081     * Adds a filter.
082     * @param filter The Filter to add.
083     */
084    @Override
085    public synchronized void addFilter(final Filter filter) {
086        if (filter == null) {
087            return;
088        }
089        if (this.filter == null) {
090            this.filter = filter;
091        } else if (this.filter instanceof CompositeFilter) {
092            this.filter = ((CompositeFilter) this.filter).addFilter(filter);
093        } else {
094            final Filter[] filters = new Filter[] {this.filter, filter};
095            this.filter = CompositeFilter.createFilters(filters);
096        }
097    }
098
099    /**
100     * Removes a Filter.
101     * @param filter The Filter to remove.
102     */
103    @Override
104    public synchronized void removeFilter(final Filter filter) {
105        if (this.filter == null || filter == null) {
106            return;
107        }
108        if (this.filter == filter || this.filter.equals(filter)) {
109            this.filter = null;
110        } else if (this.filter instanceof CompositeFilter) {
111            CompositeFilter composite = (CompositeFilter) this.filter;
112            composite = composite.removeFilter(filter);
113            if (composite.size() > 1) {
114                this.filter = composite;
115            } else if (composite.size() == 1) {
116                final Iterator<Filter> iter = composite.iterator();
117                this.filter = iter.next();
118            } else {
119                this.filter = null;
120            }
121        }
122    }
123
124    /**
125     * Determines if a Filter is present.
126     * @return false if no Filter is present.
127     */
128    @Override
129    public boolean hasFilter() {
130        return filter != null;
131    }
132
133    /**
134     * Make the Filter available for use.
135     */
136    @Override
137    public void start() {
138        this.setStarting();
139        if (filter != null) {
140            filter.start();
141        }
142        this.setStarted();
143    }
144
145    /**
146     * Cleanup the Filter.
147     */
148    @Override
149    public boolean stop(final long timeout, final TimeUnit timeUnit) {
150        return stop(timeout, timeUnit, true);
151    }
152
153    /**
154     * Cleanup the Filter.
155     */
156    protected boolean stop(final long timeout, final TimeUnit timeUnit, final boolean changeLifeCycleState) {
157        if (changeLifeCycleState) {
158            this.setStopping();
159        }
160        boolean stopped = true;
161        if (filter != null) {
162            if (filter instanceof LifeCycle2) {
163                stopped = ((LifeCycle2) filter).stop(timeout, timeUnit);
164            } else {
165                filter.stop();
166                stopped = true;
167            }
168        }
169        if (changeLifeCycleState) {
170            this.setStopped();
171        }
172        return stopped;
173    }
174
175    /**
176     * Determine if the LogEvent should be processed or ignored.
177     * @param event The LogEvent.
178     * @return true if the LogEvent should be processed.
179     */
180    @Override
181    public boolean isFiltered(final LogEvent event) {
182        return filter != null && filter.filter(event) == Filter.Result.DENY;
183    }
184
185}