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 * <p>Sets a skeleton implementation for appenders.</p>
026 *
027 * <p>It is coarsely synchronized in its {@link #doAppend(E)} method.</p>
028 * 
029 * <p>
030 * For more information about this appender, please refer to the online manual
031 * at http://logback.qos.ch/manual/appenders.html#AppenderBase
032 * 
033 * @author Ceki G&uuml;lc&uuml;
034 */
035abstract public class AppenderBase<E> extends ContextAwareBase implements Appender<E> {
036
037    protected volatile boolean started = false;
038
039    /**
040     * The guard prevents an appender from repeatedly calling its own doAppend
041     * method.
042     */
043    private boolean guard = false;
044
045    /**
046     * Appenders are named.
047     */
048    protected String name;
049
050    private FilterAttachableImpl<E> fai = new FilterAttachableImpl<E>();
051
052    public String getName() {
053        return name;
054    }
055
056    private int statusRepeatCount = 0;
057    private int exceptionCount = 0;
058
059    static final int ALLOWED_REPEATS = 5;
060
061    public synchronized void doAppend(E eventObject) {
062        // WARNING: The guard check MUST be the first statement in the
063        // doAppend() method.
064
065        // prevent re-entry.
066        if (guard) {
067            return;
068        }
069
070        try {
071            guard = true;
072
073            if (!this.started) {
074                if (statusRepeatCount++ < ALLOWED_REPEATS) {
075                    addStatus(new WarnStatus("Attempted to append to non started appender [" + name + "].", this));
076                }
077                return;
078            }
079
080            if (getFilterChainDecision(eventObject) == FilterReply.DENY) {
081                return;
082            }
083
084            // ok, we now invoke derived class' implementation of append
085            this.append(eventObject);
086
087        } catch (Exception e) {
088            if (exceptionCount++ < ALLOWED_REPEATS) {
089                addError("Appender [" + name + "] failed to append.", e);
090            }
091        } finally {
092            guard = false;
093        }
094    }
095
096    abstract protected void append(E eventObject);
097
098    /**
099     * Set the name of this appender.
100     */
101    public void setName(String name) {
102        this.name = name;
103    }
104
105    public void start() {
106        started = true;
107    }
108
109    public void stop() {
110        started = false;
111    }
112
113    public boolean isStarted() {
114        return started;
115    }
116
117    public String toString() {
118        return this.getClass().getName() + "[" + name + "]";
119    }
120
121    public void addFilter(Filter<E> newFilter) {
122        fai.addFilter(newFilter);
123    }
124
125    public void clearAllFilters() {
126        fai.clearAllFilters();
127    }
128
129    public List<Filter<E>> getCopyOfAttachedFiltersList() {
130        return fai.getCopyOfAttachedFiltersList();
131    }
132
133    public FilterReply getFilterChainDecision(E event) {
134        return fai.getFilterChainDecision(event);
135    }
136
137}