1 /**
2  * Logback: the reliable, generic, fast and flexible logging framework.
3  * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4  *
5  * This program and the accompanying materials are dual-licensed under
6  * either the terms of the Eclipse Public License v1.0 as published by
7  * the Eclipse Foundation
8  *
9  *   or (per the licensee's choosing)
10  *
11  * under the terms of the GNU Lesser General Public License version 2.1
12  * as published by the Free Software Foundation.
13  */

14 package ch.qos.logback.core;
15
16 import java.util.ArrayList;
17 import java.util.List;
18
19 import ch.qos.logback.core.helpers.CyclicBuffer;
20 import ch.qos.logback.core.spi.LogbackLock;
21 import ch.qos.logback.core.status.OnConsoleStatusListener;
22 import ch.qos.logback.core.status.Status;
23 import ch.qos.logback.core.status.StatusListener;
24 import ch.qos.logback.core.status.StatusManager;
25
26 public class BasicStatusManager implements StatusManager {
27
28     public static final int MAX_HEADER_COUNT = 150;
29     public static final int TAIL_SIZE = 150;
30
31     int count = 0;
32
33     // protected access was requested in http://jira.qos.ch/browse/LBCORE-36
34     final protected List<Status> statusList = new ArrayList<Status>();
35     final protected CyclicBuffer<Status> tailBuffer = new CyclicBuffer<Status>(TAIL_SIZE);
36     final protected LogbackLock statusListLock = new LogbackLock();
37
38     int level = Status.INFO;
39
40     // protected access was requested in http://jira.qos.ch/browse/LBCORE-36
41     final protected List<StatusListener> statusListenerList = new ArrayList<StatusListener>();
42     final protected LogbackLock statusListenerListLock = new LogbackLock();
43
44     // Note on synchronization
45     // This class contains two separate locks statusListLock and
46     // statusListenerListLock guarding respectively the statusList+tailBuffer and
47     // statusListenerList fields. The locks are used internally
48     // without cycles. They are exposed to derived classes which should be careful
49     // not to create deadlock cycles.
50
51     /**
52      * Add a new status object.
53      * 
54      * @param newStatus
55      *                the status message to add
56      */

57     public void add(Status newStatus) {
58         // LBCORE-72: fire event before the count check
59         fireStatusAddEvent(newStatus);
60
61         count++;
62         if (newStatus.getLevel() > level) {
63             level = newStatus.getLevel();
64         }
65
66         synchronized (statusListLock) {
67             if (statusList.size() < MAX_HEADER_COUNT) {
68                 statusList.add(newStatus);
69             } else {
70                 tailBuffer.add(newStatus);
71             }
72         }
73
74     }
75
76     public List<Status> getCopyOfStatusList() {
77         synchronized (statusListLock) {
78             List<Status> tList = new ArrayList<Status>(statusList);
79             tList.addAll(tailBuffer.asList());
80             return tList;
81         }
82     }
83
84     private void fireStatusAddEvent(Status status) {
85         synchronized (statusListenerListLock) {
86             for (StatusListener sl : statusListenerList) {
87                 sl.addStatusEvent(status);
88             }
89         }
90     }
91
92     public void clear() {
93         synchronized (statusListLock) {
94             count = 0;
95             statusList.clear();
96             tailBuffer.clear();
97         }
98     }
99
100     public int getLevel() {
101         return level;
102     }
103
104     public int getCount() {
105         return count;
106     }
107
108     /**
109      * This implementation does not allow duplicate installations of OnConsoleStatusListener
110      * @param listener
111      */

112     public boolean add(StatusListener listener) {
113         synchronized (statusListenerListLock) {
114             if (listener instanceof OnConsoleStatusListener) {
115                 boolean alreadyPresent = checkForPresence(statusListenerList, listener.getClass());
116                 if (alreadyPresent)
117                     return false;
118             }
119             statusListenerList.add(listener);
120         }
121         return true;
122     }
123
124     private boolean checkForPresence(List<StatusListener> statusListenerList, Class<?> aClass) {
125         for (StatusListener e : statusListenerList) {
126             if (e.getClass() == aClass)
127                 return true;
128         }
129         return false;
130     }
131
132     public void remove(StatusListener listener) {
133         synchronized (statusListenerListLock) {
134             statusListenerList.remove(listener);
135         }
136     }
137
138     public List<StatusListener> getCopyOfStatusListenerList() {
139         synchronized (statusListenerListLock) {
140             return new ArrayList<StatusListener>(statusListenerList);
141         }
142     }
143
144 }
145