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 * Similar to AppenderBase except that derived appenders need to handle 
026 * thread synchronization on their own.
027 * 
028 * @author Ceki Gülcü
029 * @author Ralph Goers
030 */
031abstract public class UnsynchronizedAppenderBase<E> extends ContextAwareBase implements Appender<E> {
032
033    protected boolean started = false;
034
035    // using a ThreadLocal instead of a boolean add 75 nanoseconds per
036    // doAppend invocation. This is tolerable as doAppend takes at least a few microseconds
037    // on a real appender
038    /**
039     * The guard prevents an appender from repeatedly calling its own doAppend
040     * method.
041     */
042    private ThreadLocal<Boolean> guard = new ThreadLocal<Boolean>();
043
044    /**
045     * Appenders are named.
046     */
047    protected String name;
048
049    private FilterAttachableImpl<E> fai = new FilterAttachableImpl<E>();
050
051    public String getName() {
052        return name;
053    }
054
055    private int statusRepeatCount = 0;
056    private int exceptionCount = 0;
057
058    static final int ALLOWED_REPEATS = 3;
059
060    public void doAppend(E eventObject) {
061        // WARNING: The guard check MUST be the first statement in the
062        // doAppend() method.
063
064        // prevent re-entry.
065        if (Boolean.TRUE.equals(guard.get())) {
066            return;
067        }
068
069        try {
070            guard.set(Boolean.TRUE);
071
072            if (!this.started) {
073                if (statusRepeatCount++ < ALLOWED_REPEATS) {
074                    addStatus(new WarnStatus("Attempted to append to non started appender [" + name + "].", this));
075                }
076                return;
077            }
078
079            if (getFilterChainDecision(eventObject) == FilterReply.DENY) {
080                return;
081            }
082
083            // ok, we now invoke derived class' implementation of append
084            this.append(eventObject);
085
086        } catch (Exception e) {
087            if (exceptionCount++ < ALLOWED_REPEATS) {
088                addError("Appender [" + name + "] failed to append.", e);
089            }
090        } finally {
091            guard.set(Boolean.FALSE);
092        }
093    }
094
095    abstract protected void append(E eventObject);
096
097    /**
098     * Set the name of this appender.
099     */
100    public void setName(String name) {
101        this.name = name;
102    }
103
104    public void start() {
105        started = true;
106    }
107
108    public void stop() {
109        started = false;
110    }
111
112    public boolean isStarted() {
113        return started;
114    }
115
116    public String toString() {
117        return this.getClass().getName() + "[" + name + "]";
118    }
119
120    public void addFilter(Filter<E> newFilter) {
121        fai.addFilter(newFilter);
122    }
123
124    public void clearAllFilters() {
125        fai.clearAllFilters();
126    }
127
128    public List<Filter<E>> getCopyOfAttachedFiltersList() {
129        return fai.getCopyOfAttachedFiltersList();
130    }
131
132    public FilterReply getFilterChainDecision(E event) {
133        return fai.getFilterChainDecision(event);
134    }
135}