001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core;
015
016import java.util.List;
017
018import ch.qos.logback.core.filter.Filter;
019import ch.qos.logback.core.spi.ContextAwareBase;
020import ch.qos.logback.core.spi.FilterAttachableImpl;
021import ch.qos.logback.core.spi.FilterReply;
022import ch.qos.logback.core.status.WarnStatus;
023
024/**
025 * Sets a skeleton implementation for appenders.
026 * 
027 * <p>
028 * For more information about this appender, please refer to the online manual
029 * at http://logback.qos.ch/manual/appenders.html#AppenderBase
030 * 
031 * @author Ceki G&uuml;lc&uuml;
032 */
033abstract public class AppenderBase<E> extends ContextAwareBase implements Appender<E> {
034
035    protected volatile boolean started = false;
036
037    /**
038     * The guard prevents an appender from repeatedly calling its own doAppend
039     * method.
040     */
041    private boolean guard = false;
042
043    /**
044     * Appenders are named.
045     */
046    protected String name;
047
048    private FilterAttachableImpl<E> fai = new FilterAttachableImpl<E>();
049
050    public String getName() {
051        return name;
052    }
053
054    private int statusRepeatCount = 0;
055    private int exceptionCount = 0;
056
057    static final int ALLOWED_REPEATS = 5;
058
059    public synchronized void doAppend(E eventObject) {
060        // WARNING: The guard check MUST be the first statement in the
061        // doAppend() method.
062
063        // prevent re-entry.
064        if (guard) {
065            return;
066        }
067
068        try {
069            guard = true;
070
071            if (!this.started) {
072                if (statusRepeatCount++ < ALLOWED_REPEATS) {
073                    addStatus(new WarnStatus("Attempted to append to non started appender [" + name + "].", this));
074                }
075                return;
076            }
077
078            if (getFilterChainDecision(eventObject) == FilterReply.DENY) {
079                return;
080            }
081
082            // ok, we now invoke derived class' implementation of append
083            this.append(eventObject);
084
085        } catch (Exception e) {
086            if (exceptionCount++ < ALLOWED_REPEATS) {
087                addError("Appender [" + name + "] failed to append.", e);
088            }
089        } finally {
090            guard = false;
091        }
092    }
093
094    abstract protected void append(E eventObject);
095
096    /**
097     * Set the name of this appender.
098     */
099    public void setName(String name) {
100        this.name = name;
101    }
102
103    public void start() {
104        started = true;
105    }
106
107    public void stop() {
108        started = false;
109    }
110
111    public boolean isStarted() {
112        return started;
113    }
114
115    public String toString() {
116        return this.getClass().getName() + "[" + name + "]";
117    }
118
119    public void addFilter(Filter<E> newFilter) {
120        fai.addFilter(newFilter);
121    }
122
123    public void clearAllFilters() {
124        fai.clearAllFilters();
125    }
126
127    public List<Filter<E>> getCopyOfAttachedFiltersList() {
128        return fai.getCopyOfAttachedFiltersList();
129    }
130
131    public FilterReply getFilterChainDecision(E event) {
132        return fai.getFilterChainDecision(event);
133    }
134
135}