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.ArrayList;
017import java.util.List;
018
019import ch.qos.logback.core.helpers.CyclicBuffer;
020import ch.qos.logback.core.spi.LogbackLock;
021import ch.qos.logback.core.status.OnConsoleStatusListener;
022import ch.qos.logback.core.status.Status;
023import ch.qos.logback.core.status.StatusListener;
024import ch.qos.logback.core.status.StatusManager;
025
026public class BasicStatusManager implements StatusManager {
027
028    public static final int MAX_HEADER_COUNT = 150;
029    public static final int TAIL_SIZE = 150;
030
031    int count = 0;
032
033    // protected access was requested in http://jira.qos.ch/browse/LBCORE-36
034    final protected List<Status> statusList = new ArrayList<Status>();
035    final protected CyclicBuffer<Status> tailBuffer = new CyclicBuffer<Status>(TAIL_SIZE);
036    final protected LogbackLock statusListLock = new LogbackLock();
037
038    int level = Status.INFO;
039
040    // protected access was requested in http://jira.qos.ch/browse/LBCORE-36
041    final protected List<StatusListener> statusListenerList = new ArrayList<StatusListener>();
042    final protected LogbackLock statusListenerListLock = new LogbackLock();
043
044    // Note on synchronization
045    // This class contains two separate locks statusListLock and
046    // statusListenerListLock guarding respectively the statusList+tailBuffer and
047    // statusListenerList fields. The locks are used internally
048    // without cycles. They are exposed to derived classes which should be careful
049    // not to create deadlock cycles.
050
051    /**
052     * Add a new status object.
053     * 
054     * @param newStatus the status message to add
055     */
056    public void add(Status newStatus) {
057        // LBCORE-72: fire event before the count check
058        fireStatusAddEvent(newStatus);
059
060        count++;
061        if (newStatus.getLevel() > level) {
062            level = newStatus.getLevel();
063        }
064
065        synchronized (statusListLock) {
066            if (statusList.size() < MAX_HEADER_COUNT) {
067                statusList.add(newStatus);
068            } else {
069                tailBuffer.add(newStatus);
070            }
071        }
072
073    }
074
075    public List<Status> getCopyOfStatusList() {
076        synchronized (statusListLock) {
077            List<Status> tList = new ArrayList<Status>(statusList);
078            tList.addAll(tailBuffer.asList());
079            return tList;
080        }
081    }
082
083    private void fireStatusAddEvent(Status status) {
084        synchronized (statusListenerListLock) {
085            for (StatusListener sl : statusListenerList) {
086                sl.addStatusEvent(status);
087            }
088        }
089    }
090
091    public void clear() {
092        synchronized (statusListLock) {
093            count = 0;
094            statusList.clear();
095            tailBuffer.clear();
096        }
097    }
098
099    public int getLevel() {
100        return level;
101    }
102
103    public int getCount() {
104        return count;
105    }
106
107    /**
108     * This implementation does not allow duplicate installations of
109     * OnConsoleStatusListener
110     * 
111     * @param listener
112     */
113    public boolean add(StatusListener listener) {
114        synchronized (statusListenerListLock) {
115            if (listener instanceof OnConsoleStatusListener) {
116                boolean alreadyPresent = checkForPresence(statusListenerList, listener.getClass());
117                if (alreadyPresent)
118                    return false;
119            }
120            statusListenerList.add(listener);
121        }
122        return true;
123    }
124
125    private boolean checkForPresence(List<StatusListener> statusListenerList, Class<?> aClass) {
126        for (StatusListener e : statusListenerList) {
127            if (e.getClass() == aClass)
128                return true;
129        }
130        return false;
131    }
132
133    public void remove(StatusListener listener) {
134        synchronized (statusListenerListLock) {
135            statusListenerList.remove(listener);
136        }
137    }
138
139    public List<StatusListener> getCopyOfStatusListenerList() {
140        synchronized (statusListenerListLock) {
141            return new ArrayList<StatusListener>(statusListenerList);
142        }
143    }
144
145}